prisma-generator-express 1.40.0 → 1.42.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 +444 -12
- package/dist/generators/generateOperationCore.d.ts +3 -1
- package/dist/generators/generateOperationCore.js +266 -160
- package/dist/generators/generateOperationCore.js.map +1 -1
- package/dist/generators/generateRouteConfigType.d.ts +3 -1
- package/dist/generators/generateRouteConfigType.js +36 -31
- package/dist/generators/generateRouteConfigType.js.map +1 -1
- package/dist/generators/generateRouter.d.ts +4 -2
- package/dist/generators/generateRouter.js +186 -132
- package/dist/generators/generateRouter.js.map +1 -1
- package/dist/generators/generateRouterFastify.d.ts +3 -1
- package/dist/generators/generateRouterFastify.js +12 -10
- package/dist/generators/generateRouterFastify.js.map +1 -1
- package/dist/generators/generateRouterHono.d.ts +3 -1
- package/dist/generators/generateRouterHono.js +12 -9
- package/dist/generators/generateRouterHono.js.map +1 -1
- package/dist/generators/generateUnifiedDocs.d.ts +2 -1
- package/dist/generators/generateUnifiedDocs.js +6 -4
- package/dist/generators/generateUnifiedDocs.js.map +1 -1
- package/dist/index.js +16 -21
- package/dist/index.js.map +1 -1
- package/dist/utils/copyFiles.d.ts +2 -1
- package/dist/utils/copyFiles.js +39 -34
- package/dist/utils/copyFiles.js.map +1 -1
- package/dist/utils/importExt.d.ts +2 -0
- package/dist/utils/importExt.js +11 -0
- package/dist/utils/importExt.js.map +1 -0
- package/dist/utils/resolveImportStyle.d.ts +3 -0
- package/dist/utils/resolveImportStyle.js +211 -0
- package/dist/utils/resolveImportStyle.js.map +1 -0
- package/dist/utils/writeFileSafely.js +6 -9
- package/dist/utils/writeFileSafely.js.map +1 -1
- package/package.json +1 -1
- package/src/copy/routeConfig.express.ts +39 -5
- package/src/copy/routeConfig.fastify.ts +8 -4
- package/src/copy/routeConfig.hono.ts +7 -3
- package/src/copy/routeConfig.ts +42 -2
- package/src/generators/generateOperationCore.ts +273 -169
- package/src/generators/generateRouteConfigType.ts +43 -36
- package/src/generators/generateRouter.ts +189 -133
- package/src/generators/generateRouterFastify.ts +14 -9
- package/src/generators/generateRouterHono.ts +14 -8
- package/src/generators/generateUnifiedDocs.ts +8 -3
- package/src/index.ts +25 -47
- package/src/utils/copyFiles.ts +45 -45
- package/src/utils/importExt.ts +7 -0
- package/src/utils/resolveImportStyle.ts +187 -0
- package/src/utils/writeFileSafely.ts +6 -22
package/README.md
CHANGED
|
@@ -12,6 +12,7 @@ Running `npx prisma generate` produces:
|
|
|
12
12
|
- Handler functions for all Prisma operations (findMany, create, update, delete, etc.)
|
|
13
13
|
- Router generator with middleware support (before/after hooks per operation)
|
|
14
14
|
- POST read endpoints for all read operations (for complex queries exceeding URL length limits)
|
|
15
|
+
- Express-only progressive read streaming over Server-Sent Events (SSE) for staged page-level responses
|
|
15
16
|
- OpenAPI 3.1 spec (JSON and YAML endpoints registered automatically per router)
|
|
16
17
|
- Documentation helpers for contract view and Scalar UI (require manual mounting)
|
|
17
18
|
- Client-side query parameter encoder
|
|
@@ -33,6 +34,7 @@ Supports **Express**, **Fastify**, and **Hono** targets via the `target` configu
|
|
|
33
34
|
- [Request body format](#request-body-format)
|
|
34
35
|
- [Query encoding (client side)](#query-encoding-client-side)
|
|
35
36
|
- [POST read endpoints](#post-read-endpoints)
|
|
37
|
+
- [Progressive Endpoint Composition (Express SSE)](#progressive-endpoint-composition-express-sse)
|
|
36
38
|
- [Response shaping: select, include, omit](#response-shaping-select-include-omit)
|
|
37
39
|
- [BigInt and Decimal handling](#bigint-and-decimal-handling)
|
|
38
40
|
- [Pagination](#pagination)
|
|
@@ -70,6 +72,8 @@ Some operations require newer versions:
|
|
|
70
72
|
|
|
71
73
|
The Hono target v1 is tested on Node.js runtimes only. See [Cloudflare Workers and edge runtimes](#cloudflare-workers-and-edge-runtimes).
|
|
72
74
|
|
|
75
|
+
Progressive Endpoint Composition over Server-Sent Events is currently supported by the Express target only. Fastify and Hono continue to support normal JSON read and write routes.
|
|
76
|
+
|
|
73
77
|
### Database provider support
|
|
74
78
|
|
|
75
79
|
Most operations work across all Prisma-supported providers. Exceptions:
|
|
@@ -1323,6 +1327,385 @@ app.use('/', UserRouter({
|
|
|
1323
1327
|
}))
|
|
1324
1328
|
```
|
|
1325
1329
|
|
|
1330
|
+
## Progressive Endpoint Composition (Express SSE)
|
|
1331
|
+
|
|
1332
|
+
Progressive Endpoint Composition lets an Express read endpoint stream partial response fields over Server-Sent Events while still ending with a final result event.
|
|
1333
|
+
|
|
1334
|
+
This is useful for page-level endpoints where different UI sections need different slices of data. For example, a dashboard can render profile basics first, then saved jobs, applications, invitations, and activity as each stage finishes.
|
|
1335
|
+
|
|
1336
|
+
This feature is **Express-only** in v1.
|
|
1337
|
+
|
|
1338
|
+
### Mental model
|
|
1339
|
+
|
|
1340
|
+
Progressive Endpoint Composition is explicit staged data loading for a specific operation variant.
|
|
1341
|
+
|
|
1342
|
+
It is **not** automatic Prisma include streaming. The generator does not split arbitrary `select` or `include` trees. You define stages yourself and each stage decides what query to run and which field path to patch.
|
|
1343
|
+
|
|
1344
|
+
### Request format
|
|
1345
|
+
|
|
1346
|
+
Use the same generated GET read endpoint and request SSE with the `Accept` header:
|
|
1347
|
+
|
|
1348
|
+
```http
|
|
1349
|
+
GET /user/first
|
|
1350
|
+
Accept: text/event-stream
|
|
1351
|
+
x-api-variant: /talent/dashboard
|
|
1352
|
+
```
|
|
1353
|
+
|
|
1354
|
+
No new endpoint is generated. The variant is resolved the same way as guard variants: `guard.resolveVariant(req)` first, then the configured header, defaulting to `x-api-variant`.
|
|
1355
|
+
|
|
1356
|
+
If a GET read request accepts `text/event-stream` but the matched variant has no progressive config, the router runs the normal read query and returns a single SSE `result` event.
|
|
1357
|
+
|
|
1358
|
+
POST read endpoints remain JSON-only.
|
|
1359
|
+
|
|
1360
|
+
### Supported operations
|
|
1361
|
+
|
|
1362
|
+
Progressive SSE can be configured on Express GET read operations only:
|
|
1363
|
+
|
|
1364
|
+
- `findMany`
|
|
1365
|
+
- `findUnique`
|
|
1366
|
+
- `findUniqueOrThrow`
|
|
1367
|
+
- `findFirst`
|
|
1368
|
+
- `findFirstOrThrow`
|
|
1369
|
+
- `findManyPaginated`
|
|
1370
|
+
- `count`
|
|
1371
|
+
- `aggregate`
|
|
1372
|
+
- `groupBy`
|
|
1373
|
+
|
|
1374
|
+
Write operations do not support progressive SSE.
|
|
1375
|
+
|
|
1376
|
+
### Event protocol
|
|
1377
|
+
|
|
1378
|
+
Each event is sent as a normal SSE `data:` line containing JSON.
|
|
1379
|
+
|
|
1380
|
+
Progress event:
|
|
1381
|
+
|
|
1382
|
+
```json
|
|
1383
|
+
{ "type": "progress", "stage": "profileBasics", "completed": 1, "total": 4 }
|
|
1384
|
+
```
|
|
1385
|
+
|
|
1386
|
+
Field event:
|
|
1387
|
+
|
|
1388
|
+
```json
|
|
1389
|
+
{ "type": "field", "key": "profile", "value": { "id": "profile-id" } }
|
|
1390
|
+
```
|
|
1391
|
+
|
|
1392
|
+
Nested field event:
|
|
1393
|
+
|
|
1394
|
+
```json
|
|
1395
|
+
{ "type": "field", "key": "profile.appliedTo", "value": [] }
|
|
1396
|
+
```
|
|
1397
|
+
|
|
1398
|
+
Final result event:
|
|
1399
|
+
|
|
1400
|
+
```json
|
|
1401
|
+
{ "type": "result", "data": { "id": "user-id", "profile": {}, "savedJobAds": [] } }
|
|
1402
|
+
```
|
|
1403
|
+
|
|
1404
|
+
Error event:
|
|
1405
|
+
|
|
1406
|
+
```json
|
|
1407
|
+
{ "type": "error", "message": "Could not load progressive response" }
|
|
1408
|
+
```
|
|
1409
|
+
|
|
1410
|
+
The final `result.data` is the accumulated object built from all applied patches, unless a stage returns a stop result.
|
|
1411
|
+
|
|
1412
|
+
### Route config example
|
|
1413
|
+
|
|
1414
|
+
Progressive config lives on an Express read operation. It is keyed by the resolved variant.
|
|
1415
|
+
|
|
1416
|
+
```ts
|
|
1417
|
+
import type { ProgressiveStage } from './generated/routeConfig.target'
|
|
1418
|
+
|
|
1419
|
+
const dashboardIdentity: ProgressiveStage<{ userId: string }> = async ({
|
|
1420
|
+
ctx,
|
|
1421
|
+
prisma,
|
|
1422
|
+
}) => {
|
|
1423
|
+
const user = await prisma.user.findFirst({
|
|
1424
|
+
select: { id: true },
|
|
1425
|
+
where: { id: ctx.userId },
|
|
1426
|
+
})
|
|
1427
|
+
|
|
1428
|
+
if (!user) {
|
|
1429
|
+
return {
|
|
1430
|
+
stop: true,
|
|
1431
|
+
data: null,
|
|
1432
|
+
}
|
|
1433
|
+
}
|
|
1434
|
+
|
|
1435
|
+
return {
|
|
1436
|
+
key: 'id',
|
|
1437
|
+
value: user.id,
|
|
1438
|
+
}
|
|
1439
|
+
}
|
|
1440
|
+
|
|
1441
|
+
const dashboardProfileBasics: ProgressiveStage<{ userId: string }> = async ({
|
|
1442
|
+
ctx,
|
|
1443
|
+
prisma,
|
|
1444
|
+
}) => {
|
|
1445
|
+
const user = await prisma.user.findFirst({
|
|
1446
|
+
select: {
|
|
1447
|
+
profile: {
|
|
1448
|
+
select: {
|
|
1449
|
+
id: true,
|
|
1450
|
+
profileName: true,
|
|
1451
|
+
profilePicture: true,
|
|
1452
|
+
jobTitle: true,
|
|
1453
|
+
location: true,
|
|
1454
|
+
skills: true,
|
|
1455
|
+
isAvailableForHire: true,
|
|
1456
|
+
_count: {
|
|
1457
|
+
select: {
|
|
1458
|
+
profileViews: true,
|
|
1459
|
+
savedAt: true,
|
|
1460
|
+
},
|
|
1461
|
+
},
|
|
1462
|
+
boost: {
|
|
1463
|
+
select: {
|
|
1464
|
+
boostedUntil: true,
|
|
1465
|
+
},
|
|
1466
|
+
},
|
|
1467
|
+
},
|
|
1468
|
+
},
|
|
1469
|
+
},
|
|
1470
|
+
where: { id: ctx.userId },
|
|
1471
|
+
})
|
|
1472
|
+
|
|
1473
|
+
return {
|
|
1474
|
+
key: 'profile',
|
|
1475
|
+
value: user?.profile
|
|
1476
|
+
? {
|
|
1477
|
+
...user.profile,
|
|
1478
|
+
appliedTo: [],
|
|
1479
|
+
invitationsFor: [],
|
|
1480
|
+
jobAdViews: [],
|
|
1481
|
+
campaign_clicks: [],
|
|
1482
|
+
jobAssignments: [],
|
|
1483
|
+
resourceOfCompanyTalentRoster: [],
|
|
1484
|
+
}
|
|
1485
|
+
: null,
|
|
1486
|
+
}
|
|
1487
|
+
}
|
|
1488
|
+
|
|
1489
|
+
const dashboardApplications: ProgressiveStage<{ userId: string }> = async ({
|
|
1490
|
+
ctx,
|
|
1491
|
+
prisma,
|
|
1492
|
+
accumulated,
|
|
1493
|
+
}) => {
|
|
1494
|
+
if (accumulated.profile == null) return
|
|
1495
|
+
|
|
1496
|
+
const profile = await prisma.talentProfile.findFirst({
|
|
1497
|
+
select: {
|
|
1498
|
+
appliedTo: {
|
|
1499
|
+
orderBy: { createdAt: 'desc' },
|
|
1500
|
+
take: 50,
|
|
1501
|
+
where: { deletedAt: null },
|
|
1502
|
+
select: {
|
|
1503
|
+
id: true,
|
|
1504
|
+
createdAt: true,
|
|
1505
|
+
viewedAt: true,
|
|
1506
|
+
details: true,
|
|
1507
|
+
jobAd: true,
|
|
1508
|
+
},
|
|
1509
|
+
},
|
|
1510
|
+
},
|
|
1511
|
+
where: { userId: ctx.userId },
|
|
1512
|
+
})
|
|
1513
|
+
|
|
1514
|
+
return {
|
|
1515
|
+
key: 'profile.appliedTo',
|
|
1516
|
+
value: profile?.appliedTo ?? [],
|
|
1517
|
+
}
|
|
1518
|
+
}
|
|
1519
|
+
|
|
1520
|
+
const userConfig = {
|
|
1521
|
+
resolveContext: (req) => ({
|
|
1522
|
+
userId: req.user.id,
|
|
1523
|
+
}),
|
|
1524
|
+
|
|
1525
|
+
guard: {
|
|
1526
|
+
variantHeader: 'x-api-variant',
|
|
1527
|
+
},
|
|
1528
|
+
|
|
1529
|
+
findFirst: {
|
|
1530
|
+
shape: {
|
|
1531
|
+
'/talent/dashboard': dashboardShape,
|
|
1532
|
+
me: meShape,
|
|
1533
|
+
},
|
|
1534
|
+
progressive: {
|
|
1535
|
+
'/talent/dashboard': {
|
|
1536
|
+
enabled: true,
|
|
1537
|
+
stages: [
|
|
1538
|
+
'dashboardIdentity',
|
|
1539
|
+
'dashboardProfileBasics',
|
|
1540
|
+
'dashboardApplications',
|
|
1541
|
+
],
|
|
1542
|
+
},
|
|
1543
|
+
},
|
|
1544
|
+
progressiveStages: {
|
|
1545
|
+
dashboardIdentity,
|
|
1546
|
+
dashboardProfileBasics,
|
|
1547
|
+
dashboardApplications,
|
|
1548
|
+
},
|
|
1549
|
+
},
|
|
1550
|
+
}
|
|
1551
|
+
|
|
1552
|
+
app.use('/', UserRouter(userConfig))
|
|
1553
|
+
```
|
|
1554
|
+
|
|
1555
|
+
`resolveContext` is required for a variant with `progressive.enabled !== false`. It is not required for ordinary JSON requests or for single-result SSE fallback.
|
|
1556
|
+
|
|
1557
|
+
### Stage function API
|
|
1558
|
+
|
|
1559
|
+
```ts
|
|
1560
|
+
type ProgressiveStageContext<TContext = unknown, TPrisma = any> = {
|
|
1561
|
+
ctx: TContext
|
|
1562
|
+
req: Request
|
|
1563
|
+
res: Response
|
|
1564
|
+
prisma: TPrisma
|
|
1565
|
+
variant: string
|
|
1566
|
+
accumulated: Record<string, unknown>
|
|
1567
|
+
signal: AbortSignal
|
|
1568
|
+
}
|
|
1569
|
+
|
|
1570
|
+
type ProgressivePatch = {
|
|
1571
|
+
key: string
|
|
1572
|
+
value: unknown
|
|
1573
|
+
}
|
|
1574
|
+
|
|
1575
|
+
type ProgressiveStopResult<T = unknown> = {
|
|
1576
|
+
stop: true
|
|
1577
|
+
data: T
|
|
1578
|
+
}
|
|
1579
|
+
|
|
1580
|
+
type ProgressiveStageResult<T = unknown> =
|
|
1581
|
+
| void
|
|
1582
|
+
| ProgressivePatch
|
|
1583
|
+
| ProgressivePatch[]
|
|
1584
|
+
| ProgressiveStopResult<T>
|
|
1585
|
+
|
|
1586
|
+
type ProgressiveStage<TContext = unknown, TPrisma = any, T = unknown> = (
|
|
1587
|
+
context: ProgressiveStageContext<TContext, TPrisma>,
|
|
1588
|
+
) => Promise<ProgressiveStageResult<T>>
|
|
1589
|
+
```
|
|
1590
|
+
|
|
1591
|
+
A stage may return:
|
|
1592
|
+
|
|
1593
|
+
- `void` — no patch for this stage
|
|
1594
|
+
- one `{ key, value }` patch
|
|
1595
|
+
- an array of patches
|
|
1596
|
+
- `{ stop: true, data }` to immediately send a final `result` event and stop executing later stages
|
|
1597
|
+
|
|
1598
|
+
### Patch path behavior
|
|
1599
|
+
|
|
1600
|
+
Patch keys use dot paths, for example `profile.appliedTo`.
|
|
1601
|
+
|
|
1602
|
+
Nested patches require the parent object to already exist in `accumulated`. If a stage tries to patch through `null`, `undefined`, an array, a primitive, or a non-plain object, the patch is dropped and no `field` event is sent.
|
|
1603
|
+
|
|
1604
|
+
This means parent objects should be initialized by earlier stages:
|
|
1605
|
+
|
|
1606
|
+
```ts
|
|
1607
|
+
return {
|
|
1608
|
+
key: 'profile',
|
|
1609
|
+
value: {
|
|
1610
|
+
...profileBasics,
|
|
1611
|
+
appliedTo: [],
|
|
1612
|
+
invitationsFor: [],
|
|
1613
|
+
},
|
|
1614
|
+
}
|
|
1615
|
+
```
|
|
1616
|
+
|
|
1617
|
+
Patch path segments `__proto__`, `constructor`, `prototype`, and empty path segments are rejected.
|
|
1618
|
+
|
|
1619
|
+
### Hooks and guard behavior
|
|
1620
|
+
|
|
1621
|
+
For SSE requests:
|
|
1622
|
+
|
|
1623
|
+
- `before` hooks run before streaming starts
|
|
1624
|
+
- `after` hooks do not run, because the SSE middleware handles the response and does not continue to the normal handler
|
|
1625
|
+
- progressive stages receive `req.prisma` directly
|
|
1626
|
+
- guard shapes are not automatically applied to stage queries
|
|
1627
|
+
|
|
1628
|
+
Stage authors are responsible for using the resolved context and enforcing ownership or tenant constraints in their stage queries.
|
|
1629
|
+
|
|
1630
|
+
For variants without progressive config, the single-result SSE fallback uses the normal generated core read handler, so guard shape behavior matches the JSON endpoint.
|
|
1631
|
+
|
|
1632
|
+
### Client-side usage
|
|
1633
|
+
|
|
1634
|
+
Use `fetch` with streaming. Native browser `EventSource` cannot send custom headers like `x-api-variant`.
|
|
1635
|
+
|
|
1636
|
+
Minimal example:
|
|
1637
|
+
|
|
1638
|
+
```ts
|
|
1639
|
+
const response = await fetch('/user/first', {
|
|
1640
|
+
headers: {
|
|
1641
|
+
Accept: 'text/event-stream',
|
|
1642
|
+
'x-api-variant': '/talent/dashboard',
|
|
1643
|
+
},
|
|
1644
|
+
})
|
|
1645
|
+
|
|
1646
|
+
if (!response.body) {
|
|
1647
|
+
throw new Error('ReadableStream is not available')
|
|
1648
|
+
}
|
|
1649
|
+
|
|
1650
|
+
const reader = response.body.getReader()
|
|
1651
|
+
const decoder = new TextDecoder()
|
|
1652
|
+
let buffer = ''
|
|
1653
|
+
|
|
1654
|
+
while (true) {
|
|
1655
|
+
const { value, done } = await reader.read()
|
|
1656
|
+
if (done) break
|
|
1657
|
+
|
|
1658
|
+
buffer += decoder.decode(value, { stream: true })
|
|
1659
|
+
const parts = buffer.split('\n\n')
|
|
1660
|
+
buffer = parts.pop() ?? ''
|
|
1661
|
+
|
|
1662
|
+
for (const part of parts) {
|
|
1663
|
+
const line = part
|
|
1664
|
+
.split('\n')
|
|
1665
|
+
.find((entry) => entry.startsWith('data: '))
|
|
1666
|
+
|
|
1667
|
+
if (!line) continue
|
|
1668
|
+
|
|
1669
|
+
const event = JSON.parse(line.slice('data: '.length))
|
|
1670
|
+
|
|
1671
|
+
if (event.type === 'field') {
|
|
1672
|
+
// patch local field state
|
|
1673
|
+
}
|
|
1674
|
+
|
|
1675
|
+
if (event.type === 'result') {
|
|
1676
|
+
// replace with final result
|
|
1677
|
+
}
|
|
1678
|
+
}
|
|
1679
|
+
}
|
|
1680
|
+
```
|
|
1681
|
+
|
|
1682
|
+
For React Query, include the variant and mode in the query key:
|
|
1683
|
+
|
|
1684
|
+
```ts
|
|
1685
|
+
['user', 'first', { variant: '/talent/dashboard', mode: 'sse' }]
|
|
1686
|
+
```
|
|
1687
|
+
|
|
1688
|
+
Do not reuse the same query key as the JSON endpoint because the same URL can return different shapes depending on `x-api-variant`.
|
|
1689
|
+
|
|
1690
|
+
### Runtime notes
|
|
1691
|
+
|
|
1692
|
+
The SSE response sets:
|
|
1693
|
+
|
|
1694
|
+
```http
|
|
1695
|
+
Content-Type: text/event-stream
|
|
1696
|
+
Cache-Control: no-cache, no-transform
|
|
1697
|
+
Connection: keep-alive
|
|
1698
|
+
X-Accel-Buffering: no
|
|
1699
|
+
```
|
|
1700
|
+
|
|
1701
|
+
The server sends keepalive comments periodically:
|
|
1702
|
+
|
|
1703
|
+
```txt
|
|
1704
|
+
: keepalive
|
|
1705
|
+
```
|
|
1706
|
+
|
|
1707
|
+
If compression middleware is used, configure it to skip `text/event-stream`, or ensure `res.flush()` is available so events are flushed promptly.
|
|
1708
|
+
|
|
1326
1709
|
## Response shaping: select, include, omit
|
|
1327
1710
|
|
|
1328
1711
|
Read and single-record write operations support three response shaping parameters:
|
|
@@ -1615,7 +1998,8 @@ app.use('*', async (c, next) => {
|
|
|
1615
1998
|
c.set('prisma', prisma)
|
|
1616
1999
|
c.set('postgres', sql)
|
|
1617
2000
|
await next()
|
|
1618
|
-
})
|
|
2001
|
+
})
|
|
2002
|
+
```
|
|
1619
2003
|
|
|
1620
2004
|
Without a connector on the request context, the handlers use the standard PrismaClient. Set `DEBUG=true` in the environment to enable prisma-sql debug logging.
|
|
1621
2005
|
|
|
@@ -1667,6 +2051,8 @@ Paths shown are relative suffixes. Actual paths include the model prefix (e.g.,
|
|
|
1667
2051
|
|
|
1668
2052
|
POST read endpoints are enabled by default. Set `disablePostReads: true` to remove them.
|
|
1669
2053
|
|
|
2054
|
+
For the Express target, GET read endpoints can also stream SSE events when the request sends `Accept: text/event-stream`. SSE uses the same GET paths shown above; no additional routes are generated. See [Progressive Endpoint Composition](#progressive-endpoint-composition-express-sse).
|
|
2055
|
+
|
|
1670
2056
|
## Skipping models
|
|
1671
2057
|
|
|
1672
2058
|
Add `/// generator off` to a model's documentation to skip generation:
|
|
@@ -1683,7 +2069,7 @@ model InternalLog {
|
|
|
1683
2069
|
### Express
|
|
1684
2070
|
|
|
1685
2071
|
```ts
|
|
1686
|
-
interface RouteConfig {
|
|
2072
|
+
interface RouteConfig<TCtx = unknown> {
|
|
1687
2073
|
enableAll?: boolean
|
|
1688
2074
|
addModelPrefix?: boolean // default: true
|
|
1689
2075
|
customUrlPrefix?: string
|
|
@@ -1704,6 +2090,8 @@ interface RouteConfig {
|
|
|
1704
2090
|
variantHeader?: string // default: 'x-api-variant'
|
|
1705
2091
|
}
|
|
1706
2092
|
|
|
2093
|
+
resolveContext?: (req: Request) => TCtx | Promise<TCtx>
|
|
2094
|
+
|
|
1707
2095
|
queryBuilder?: QueryBuilderConfig | false
|
|
1708
2096
|
|
|
1709
2097
|
pagination?: {
|
|
@@ -1712,13 +2100,18 @@ interface RouteConfig {
|
|
|
1712
2100
|
distinctCountLimit?: number // default: 100000
|
|
1713
2101
|
}
|
|
1714
2102
|
|
|
1715
|
-
//
|
|
1716
|
-
findMany?:
|
|
1717
|
-
findUnique?:
|
|
1718
|
-
findUniqueOrThrow?:
|
|
1719
|
-
findFirst?:
|
|
1720
|
-
findFirstOrThrow?:
|
|
1721
|
-
findManyPaginated?:
|
|
2103
|
+
// read operation config
|
|
2104
|
+
findMany?: ReadOperationConfig<TCtx>
|
|
2105
|
+
findUnique?: ReadOperationConfig<TCtx>
|
|
2106
|
+
findUniqueOrThrow?: ReadOperationConfig<TCtx>
|
|
2107
|
+
findFirst?: ReadOperationConfig<TCtx>
|
|
2108
|
+
findFirstOrThrow?: ReadOperationConfig<TCtx>
|
|
2109
|
+
findManyPaginated?: ReadOperationConfig<TCtx>
|
|
2110
|
+
aggregate?: ReadOperationConfig<TCtx>
|
|
2111
|
+
count?: ReadOperationConfig<TCtx>
|
|
2112
|
+
groupBy?: ReadOperationConfig<TCtx>
|
|
2113
|
+
|
|
2114
|
+
// write operation config
|
|
1722
2115
|
create?: OperationConfig
|
|
1723
2116
|
createMany?: OperationConfig
|
|
1724
2117
|
createManyAndReturn?: OperationConfig
|
|
@@ -1728,9 +2121,6 @@ interface RouteConfig {
|
|
|
1728
2121
|
upsert?: OperationConfig
|
|
1729
2122
|
delete?: OperationConfig
|
|
1730
2123
|
deleteMany?: OperationConfig
|
|
1731
|
-
aggregate?: OperationConfig
|
|
1732
|
-
count?: OperationConfig
|
|
1733
|
-
groupBy?: OperationConfig
|
|
1734
2124
|
}
|
|
1735
2125
|
|
|
1736
2126
|
interface OperationConfig {
|
|
@@ -1739,6 +2129,46 @@ interface OperationConfig {
|
|
|
1739
2129
|
shape?: Record<string, any>
|
|
1740
2130
|
}
|
|
1741
2131
|
|
|
2132
|
+
interface ReadOperationConfig<TCtx = unknown> extends OperationConfig {
|
|
2133
|
+
progressive?: Record<string, ProgressiveVariantConfig>
|
|
2134
|
+
progressiveStages?: Record<string, ProgressiveStage<TCtx>>
|
|
2135
|
+
}
|
|
2136
|
+
|
|
2137
|
+
type ProgressiveVariantConfig = {
|
|
2138
|
+
enabled?: boolean
|
|
2139
|
+
stages: string[]
|
|
2140
|
+
}
|
|
2141
|
+
|
|
2142
|
+
type ProgressiveStageContext<TContext = unknown, TPrisma = any> = {
|
|
2143
|
+
ctx: TContext
|
|
2144
|
+
req: Request
|
|
2145
|
+
res: Response
|
|
2146
|
+
prisma: TPrisma
|
|
2147
|
+
variant: string
|
|
2148
|
+
accumulated: Record<string, unknown>
|
|
2149
|
+
signal: AbortSignal
|
|
2150
|
+
}
|
|
2151
|
+
|
|
2152
|
+
type ProgressivePatch = {
|
|
2153
|
+
key: string
|
|
2154
|
+
value: unknown
|
|
2155
|
+
}
|
|
2156
|
+
|
|
2157
|
+
type ProgressiveStopResult<T = unknown> = {
|
|
2158
|
+
stop: true
|
|
2159
|
+
data: T
|
|
2160
|
+
}
|
|
2161
|
+
|
|
2162
|
+
type ProgressiveStageResult<T = unknown> =
|
|
2163
|
+
| void
|
|
2164
|
+
| ProgressivePatch
|
|
2165
|
+
| ProgressivePatch[]
|
|
2166
|
+
| ProgressiveStopResult<T>
|
|
2167
|
+
|
|
2168
|
+
type ProgressiveStage<TContext = unknown, TPrisma = any, T = unknown> = (
|
|
2169
|
+
context: ProgressiveStageContext<TContext, TPrisma>,
|
|
2170
|
+
) => Promise<ProgressiveStageResult<T>>
|
|
2171
|
+
|
|
1742
2172
|
interface QueryBuilderConfig {
|
|
1743
2173
|
enabled?: boolean
|
|
1744
2174
|
port?: number
|
|
@@ -1796,6 +2226,8 @@ The Hono router does not auto-start the Query Builder. Set `queryBuilder: false`
|
|
|
1796
2226
|
|
|
1797
2227
|
`disablePostReads` removes all POST read endpoints when set to `true`. POST read endpoints are enabled by default. This is a global setting — there is no per-operation toggle.
|
|
1798
2228
|
|
|
2229
|
+
`resolveContext` is Express-only and is required for enabled progressive SSE variants. It is called before progressive stages run and its return value is passed to each stage as `ctx`.
|
|
2230
|
+
|
|
1799
2231
|
`openApiServers` sets the `servers` array in the OpenAPI spec:
|
|
1800
2232
|
|
|
1801
2233
|
```ts
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { DMMF } from '@prisma/generator-helper';
|
|
2
|
-
|
|
2
|
+
import { ImportStyle } from '../utils/resolveImportStyle';
|
|
3
|
+
export declare function generateOperationRuntime(importStyle: ImportStyle): string;
|
|
3
4
|
export interface ModelCoreOptions {
|
|
4
5
|
model: DMMF.Model;
|
|
6
|
+
importStyle: ImportStyle;
|
|
5
7
|
}
|
|
6
8
|
export declare function generateModelCore(options: ModelCoreOptions): string;
|