@vurb/prisma-gen 3.1.31
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 +83 -0
- package/dist/emitter/PresenterEmitter.d.ts +27 -0
- package/dist/emitter/PresenterEmitter.d.ts.map +1 -0
- package/dist/emitter/PresenterEmitter.js +92 -0
- package/dist/emitter/PresenterEmitter.js.map +1 -0
- package/dist/emitter/ToolEmitter.d.ts +31 -0
- package/dist/emitter/ToolEmitter.d.ts.map +1 -0
- package/dist/emitter/ToolEmitter.js +266 -0
- package/dist/emitter/ToolEmitter.js.map +1 -0
- package/dist/generator.d.ts +3 -0
- package/dist/generator.d.ts.map +1 -0
- package/dist/generator.js +81 -0
- package/dist/generator.js.map +1 -0
- package/dist/helpers/NamingHelpers.d.ts +24 -0
- package/dist/helpers/NamingHelpers.d.ts.map +1 -0
- package/dist/helpers/NamingHelpers.js +42 -0
- package/dist/helpers/NamingHelpers.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/parser/AnnotationParser.d.ts +53 -0
- package/dist/parser/AnnotationParser.d.ts.map +1 -0
- package/dist/parser/AnnotationParser.js +49 -0
- package/dist/parser/AnnotationParser.js.map +1 -0
- package/dist/types.d.ts +10 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/package.json +67 -0
package/README.md
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<h1 align="center">@vurb/prisma-gen</h1>
|
|
3
|
+
<p align="center">
|
|
4
|
+
<strong>Prisma Schema → MCP Tools Generator</strong> — Compile-time CRUD generation with field-level security
|
|
5
|
+
</p>
|
|
6
|
+
</p>
|
|
7
|
+
|
|
8
|
+
<p align="center">
|
|
9
|
+
<a href="https://www.npmjs.com/package/@vurb/prisma-gen"><img src="https://img.shields.io/npm/v/@vurb/prisma-gen?color=blue" alt="npm" /></a>
|
|
10
|
+
<a href="https://github.com/vinkius-labs/vurb.ts/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-Apache--2.0-green" alt="License" /></a>
|
|
11
|
+
<img src="https://img.shields.io/badge/node-%3E%3D18-brightgreen" alt="Node" />
|
|
12
|
+
</p>
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
> A compile-time Prisma Generator that reads `schema.prisma` annotations and emits hardened Vurb.ts Presenters and ToolBuilders — with field-level security, tenant isolation, and OOM protection baked into the generated code.
|
|
17
|
+
|
|
18
|
+
## Quick Start
|
|
19
|
+
|
|
20
|
+
```prisma
|
|
21
|
+
generator mcp {
|
|
22
|
+
provider = "vurb-prisma-gen"
|
|
23
|
+
output = "../src/tools/database"
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
model User {
|
|
27
|
+
id String @id @default(uuid())
|
|
28
|
+
email String @unique
|
|
29
|
+
passwordHash String /// @vurb.hide
|
|
30
|
+
stripeToken String /// @vurb.hide
|
|
31
|
+
creditScore Int /// @vurb.describe("Score 0-1000. Above 700 is PREMIUM.")
|
|
32
|
+
tenantId String /// @vurb.tenantKey
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npx prisma generate
|
|
38
|
+
# → src/tools/database/userPresenter.ts
|
|
39
|
+
# → src/tools/database/userTools.ts
|
|
40
|
+
# → src/tools/database/index.ts
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Features
|
|
44
|
+
|
|
45
|
+
| Feature | Description |
|
|
46
|
+
|---------|-------------|
|
|
47
|
+
| **Egress Firewall** | `@vurb.hide` physically excludes columns from the generated Zod response schema — SOC2 at compile time |
|
|
48
|
+
| **Semantic Descriptions** | `@vurb.describe("...")` injects domain semantics into generated Zod fields |
|
|
49
|
+
| **Tenant Isolation** | `@vurb.tenantKey` injects tenant filters into every query's WHERE clause |
|
|
50
|
+
| **OOM Guard** | Pagination enforced with `take` (capped at 50) and `skip` — unbounded queries are structurally impossible |
|
|
51
|
+
| **Inversion of Control** | Generates `ToolBuilder` + `Presenter` files, not a server. You wire them in |
|
|
52
|
+
|
|
53
|
+
## Schema Annotations
|
|
54
|
+
|
|
55
|
+
| Annotation | Effect |
|
|
56
|
+
|---|---|
|
|
57
|
+
| `/// @vurb.hide` | Excludes the field from the generated Zod response schema |
|
|
58
|
+
| `/// @vurb.describe("...")` | Adds `.describe()` to the Zod field — LLM reads this as a business rule |
|
|
59
|
+
| `/// @vurb.tenantKey` | Injects the field into every query's `WHERE` clause from `ctx` |
|
|
60
|
+
|
|
61
|
+
## Installation
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
npm install @vurb/prisma-gen vurb zod
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Peer Dependencies
|
|
68
|
+
|
|
69
|
+
| Package | Version |
|
|
70
|
+
|---------|---------|
|
|
71
|
+
| `vurb` | `^2.0.0` |
|
|
72
|
+
| `zod` | `^3.25.1 \|\| ^4.0.0` |
|
|
73
|
+
| `prisma` | `^6.0.0` |
|
|
74
|
+
|
|
75
|
+
## Requirements
|
|
76
|
+
|
|
77
|
+
- **Node.js** ≥ 18.0.0
|
|
78
|
+
- **Vurb.ts** ≥ 2.0.0 (peer dependency)
|
|
79
|
+
- **Prisma** ≥ 6.0.0
|
|
80
|
+
|
|
81
|
+
## License
|
|
82
|
+
|
|
83
|
+
[Apache-2.0](https://github.com/vinkius-labs/vurb.ts/blob/main/LICENSE)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PresenterEmitter — Generates Presenter files (MVA View Layer)
|
|
3
|
+
*
|
|
4
|
+
* For each Prisma model, emits a `{model}Presenter.ts` file containing:
|
|
5
|
+
* 1. A strict Zod **ResponseSchema** — the Egress Firewall
|
|
6
|
+
* 2. A `createPresenter()` binding with systemRules
|
|
7
|
+
*
|
|
8
|
+
* Security rules:
|
|
9
|
+
* - Fields with `@vurb.hide` are physically absent from the schema
|
|
10
|
+
* - Fields with `kind !== 'scalar' && kind !== 'enum'` are filtered (flat-only MVA)
|
|
11
|
+
* - Fields with `@vurb.describe("...")` get `.describe()` calls
|
|
12
|
+
* - Schema uses `.strict()` to reject undeclared fields at runtime
|
|
13
|
+
*
|
|
14
|
+
* @module
|
|
15
|
+
*/
|
|
16
|
+
import type { DMMFModel, ModelAnnotations } from '../parser/AnnotationParser.js';
|
|
17
|
+
import type { GeneratedFile } from '../types.js';
|
|
18
|
+
export type { GeneratedFile } from '../types.js';
|
|
19
|
+
/**
|
|
20
|
+
* Generate a Presenter file for a single Prisma model.
|
|
21
|
+
*
|
|
22
|
+
* @param model - Prisma DMMF model
|
|
23
|
+
* @param annotations - Parsed @vurb.* annotations
|
|
24
|
+
* @returns Generated file with path and content
|
|
25
|
+
*/
|
|
26
|
+
export declare function emitPresenter(model: DMMFModel, annotations: ModelAnnotations): GeneratedFile;
|
|
27
|
+
//# sourceMappingURL=PresenterEmitter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PresenterEmitter.d.ts","sourceRoot":"","sources":["../../src/emitter/PresenterEmitter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,EAAE,SAAS,EAAa,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAC5F,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAGjD,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAmCjD;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,gBAAgB,GAAG,aAAa,CAiE5F"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { toPascalCase } from '../helpers/NamingHelpers.js';
|
|
2
|
+
// ── Type Mapping ─────────────────────────────────────────
|
|
3
|
+
/**
|
|
4
|
+
* Map Prisma scalar type to Zod builder expression.
|
|
5
|
+
*/
|
|
6
|
+
function prismaTypeToZod(field) {
|
|
7
|
+
const base = mapScalarType(field.type);
|
|
8
|
+
// Apply .describe() if annotation exists (done externally)
|
|
9
|
+
// Apply .optional() if not required
|
|
10
|
+
if (!field.isRequired) {
|
|
11
|
+
return `${base}.optional()`;
|
|
12
|
+
}
|
|
13
|
+
return base;
|
|
14
|
+
}
|
|
15
|
+
function mapScalarType(prismaType) {
|
|
16
|
+
switch (prismaType) {
|
|
17
|
+
case 'String': return 'z.string()';
|
|
18
|
+
case 'Int': return 'z.number().int()';
|
|
19
|
+
case 'Float': return 'z.number()';
|
|
20
|
+
case 'Decimal': return 'z.number()';
|
|
21
|
+
case 'Boolean': return 'z.boolean()';
|
|
22
|
+
case 'DateTime': return 'z.coerce.date()';
|
|
23
|
+
case 'BigInt': return 'z.bigint()';
|
|
24
|
+
case 'Json': return 'z.unknown()';
|
|
25
|
+
case 'Bytes': return 'z.instanceof(Buffer)';
|
|
26
|
+
default: return 'z.string()'; // Enums fall through to z.string()
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
// ── Public API ───────────────────────────────────────────
|
|
30
|
+
/**
|
|
31
|
+
* Generate a Presenter file for a single Prisma model.
|
|
32
|
+
*
|
|
33
|
+
* @param model - Prisma DMMF model
|
|
34
|
+
* @param annotations - Parsed @vurb.* annotations
|
|
35
|
+
* @returns Generated file with path and content
|
|
36
|
+
*/
|
|
37
|
+
export function emitPresenter(model, annotations) {
|
|
38
|
+
const name = toPascalCase(model.name);
|
|
39
|
+
const lines = [];
|
|
40
|
+
// ── Imports ───────────────────────────────────────────
|
|
41
|
+
lines.push(`/**`);
|
|
42
|
+
lines.push(` * ${name}Presenter — Generated by vurb-prisma-gen`);
|
|
43
|
+
lines.push(` *`);
|
|
44
|
+
lines.push(` * Egress Firewall: fields marked @vurb.hide are physically absent.`);
|
|
45
|
+
lines.push(` * This file is auto-generated. Manual edits will be overwritten.`);
|
|
46
|
+
lines.push(` *`);
|
|
47
|
+
lines.push(` * @generated`);
|
|
48
|
+
lines.push(` */`);
|
|
49
|
+
lines.push(`import { z } from 'zod';`);
|
|
50
|
+
lines.push(`import { createPresenter } from 'vurb';`);
|
|
51
|
+
lines.push(``);
|
|
52
|
+
// ── Response Schema ──────────────────────────────────
|
|
53
|
+
lines.push(`// ── Response Schema (Egress Firewall) ────────────────────`);
|
|
54
|
+
lines.push(``);
|
|
55
|
+
lines.push(`export const ${name}ResponseSchema = z.object({`);
|
|
56
|
+
// Filter: scalar/enum only (flat-only MVA — no relations)
|
|
57
|
+
const scalarFields = model.fields.filter(f => f.kind === 'scalar' || f.kind === 'enum');
|
|
58
|
+
for (const field of scalarFields) {
|
|
59
|
+
const ann = annotations.fields.get(field.name);
|
|
60
|
+
// @vurb.hide — physically exclude from Response
|
|
61
|
+
if (ann?.hidden)
|
|
62
|
+
continue;
|
|
63
|
+
let zodExpr = prismaTypeToZod(field);
|
|
64
|
+
// @vurb.describe — inject .describe() for LLM semantics
|
|
65
|
+
if (ann?.description) {
|
|
66
|
+
const escaped = ann.description.replace(/'/g, "\\'");
|
|
67
|
+
// Insert .describe() before .optional() if present
|
|
68
|
+
if (zodExpr.endsWith('.optional()')) {
|
|
69
|
+
const base = zodExpr.slice(0, -'.optional()'.length);
|
|
70
|
+
zodExpr = `${base}.describe('${escaped}').optional()`;
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
zodExpr = `${zodExpr}.describe('${escaped}')`;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
lines.push(` ${field.name}: ${zodExpr},`);
|
|
77
|
+
}
|
|
78
|
+
lines.push(`}).strict();`);
|
|
79
|
+
lines.push(``);
|
|
80
|
+
// ── Presenter ────────────────────────────────────────
|
|
81
|
+
lines.push(`// ── Presenter ────────────────────────────────────────────`);
|
|
82
|
+
lines.push(``);
|
|
83
|
+
lines.push(`export const ${name}Presenter = createPresenter('${name}')`);
|
|
84
|
+
lines.push(` .schema(${name}ResponseSchema)`);
|
|
85
|
+
lines.push(` .systemRules(['Data originates from the database via Prisma ORM.']);`);
|
|
86
|
+
lines.push(``);
|
|
87
|
+
return {
|
|
88
|
+
path: `${model.name.charAt(0).toLowerCase() + model.name.slice(1)}Presenter.ts`,
|
|
89
|
+
content: lines.join('\n'),
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=PresenterEmitter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PresenterEmitter.js","sourceRoot":"","sources":["../../src/emitter/PresenterEmitter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ToolEmitter — Generates Tool files (MVA Agent Layer)
|
|
3
|
+
*
|
|
4
|
+
* For each Prisma model, emits a `{model}Tools.ts` file containing:
|
|
5
|
+
* 1. `PrismaVurbContext` type — shift-left TS safety for ctx.prisma + ctx.tenantId
|
|
6
|
+
* 2. `CreateSchema` — input params (no @id/@default, no @vurb.tenantKey, YES @vurb.hide)
|
|
7
|
+
* 3. `UpdateSchema` — all Create fields as .optional()
|
|
8
|
+
* 4. 5 CRUD actions: find_many, find_unique, create, update, delete
|
|
9
|
+
*
|
|
10
|
+
* Security rules:
|
|
11
|
+
* - Schema asymmetry: ResponseSchema ≠ CreateSchema ≠ UpdateSchema
|
|
12
|
+
* - @vurb.tenantKey → injected into WHERE/data of every query from ctx
|
|
13
|
+
* - @id @default fields → excluded from CreateSchema (server/DB generates)
|
|
14
|
+
* - find_many → forced pagination: take max 50, skip default 0
|
|
15
|
+
* - delete → destructive: true
|
|
16
|
+
* - find_many/find_unique → readOnly: true
|
|
17
|
+
* - Relations filtered (scalar/enum only)
|
|
18
|
+
*
|
|
19
|
+
* @module
|
|
20
|
+
*/
|
|
21
|
+
import type { DMMFModel, ModelAnnotations } from '../parser/AnnotationParser.js';
|
|
22
|
+
import type { GeneratedFile } from '../types.js';
|
|
23
|
+
/**
|
|
24
|
+
* Generate a Tool file for a single Prisma model.
|
|
25
|
+
*
|
|
26
|
+
* @param model - Prisma DMMF model
|
|
27
|
+
* @param annotations - Parsed @vurb.* annotations
|
|
28
|
+
* @returns Generated file with path and content
|
|
29
|
+
*/
|
|
30
|
+
export declare function emitTool(model: DMMFModel, annotations: ModelAnnotations): GeneratedFile;
|
|
31
|
+
//# sourceMappingURL=ToolEmitter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ToolEmitter.d.ts","sourceRoot":"","sources":["../../src/emitter/ToolEmitter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,KAAK,EAAE,SAAS,EAAa,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAC5F,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AA6CjD;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,gBAAgB,GAAG,aAAa,CAqEvF"}
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
import { toPascalCase, toSnakeCase } from '../helpers/NamingHelpers.js';
|
|
2
|
+
// ── Type Mapping ─────────────────────────────────────────
|
|
3
|
+
function mapScalarType(prismaType) {
|
|
4
|
+
switch (prismaType) {
|
|
5
|
+
case 'String': return 'z.string()';
|
|
6
|
+
case 'Int': return 'z.number().int()';
|
|
7
|
+
case 'Float': return 'z.number()';
|
|
8
|
+
case 'Decimal': return 'z.number()';
|
|
9
|
+
case 'Boolean': return 'z.boolean()';
|
|
10
|
+
case 'DateTime': return 'z.coerce.date()';
|
|
11
|
+
case 'BigInt': return 'z.bigint()';
|
|
12
|
+
case 'Json': return 'z.unknown()';
|
|
13
|
+
case 'Bytes': return 'z.instanceof(Buffer)';
|
|
14
|
+
default: return 'z.string()';
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
// ── Field Classification ─────────────────────────────────
|
|
18
|
+
/**
|
|
19
|
+
* Determine if a field should be excluded from CreateSchema.
|
|
20
|
+
* Excludes: @id with @default, @vurb.tenantKey, auto-generated timestamps.
|
|
21
|
+
*/
|
|
22
|
+
function isAutoGenerated(field, annotations) {
|
|
23
|
+
const ann = annotations.fields.get(field.name);
|
|
24
|
+
// @id with default value (uuid, autoincrement, cuid, etc.)
|
|
25
|
+
if (field.isId && field.hasDefaultValue)
|
|
26
|
+
return true;
|
|
27
|
+
// @vurb.tenantKey — injected from ctx, not from LLM
|
|
28
|
+
if (ann?.tenantKey)
|
|
29
|
+
return true;
|
|
30
|
+
// Common auto-generated timestamp fields
|
|
31
|
+
if (field.hasDefaultValue && (field.name === 'createdAt' || field.name === 'updatedAt')) {
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
// ── Public API ───────────────────────────────────────────
|
|
37
|
+
/**
|
|
38
|
+
* Generate a Tool file for a single Prisma model.
|
|
39
|
+
*
|
|
40
|
+
* @param model - Prisma DMMF model
|
|
41
|
+
* @param annotations - Parsed @vurb.* annotations
|
|
42
|
+
* @returns Generated file with path and content
|
|
43
|
+
*/
|
|
44
|
+
export function emitTool(model, annotations) {
|
|
45
|
+
const name = toPascalCase(model.name);
|
|
46
|
+
const snakeName = toSnakeCase(model.name);
|
|
47
|
+
const prismaModel = model.name.charAt(0).toLowerCase() + model.name.slice(1);
|
|
48
|
+
const lines = [];
|
|
49
|
+
// ── Header ───────────────────────────────────────────
|
|
50
|
+
lines.push(`/**`);
|
|
51
|
+
lines.push(` * ${name}Tools — Generated by vurb-prisma-gen`);
|
|
52
|
+
lines.push(` *`);
|
|
53
|
+
lines.push(` * CRUD tool with tenant isolation and OOM protection.`);
|
|
54
|
+
lines.push(` * This file is auto-generated. Manual edits will be overwritten.`);
|
|
55
|
+
lines.push(` *`);
|
|
56
|
+
lines.push(` * @generated`);
|
|
57
|
+
lines.push(` */`);
|
|
58
|
+
lines.push(`import { z } from 'zod';`);
|
|
59
|
+
lines.push(`import { defineTool } from 'vurb';`);
|
|
60
|
+
lines.push(`import { ${name}Presenter } from './${prismaModel}Presenter.js';`);
|
|
61
|
+
lines.push(``);
|
|
62
|
+
// ── Context Type (Shift-Left Security) ───────────────
|
|
63
|
+
emitContextType(lines, annotations);
|
|
64
|
+
// ── Scalar fields ────────────────────────────────────
|
|
65
|
+
const scalarFields = model.fields.filter(f => f.kind === 'scalar' || f.kind === 'enum');
|
|
66
|
+
// Fields for CreateSchema: exclude auto-generated, include @vurb.hide
|
|
67
|
+
const createFields = scalarFields.filter(f => !isAutoGenerated(f, annotations));
|
|
68
|
+
// Find the @id field for find_unique/update/delete
|
|
69
|
+
const idField = scalarFields.find(f => f.isId);
|
|
70
|
+
const idName = idField?.name ?? 'id';
|
|
71
|
+
const idZod = idField ? mapScalarType(idField.type) : 'z.string()';
|
|
72
|
+
// Filterable fields for find_many (string fields, excluding hidden and tenant)
|
|
73
|
+
const filterableFields = scalarFields.filter(f => {
|
|
74
|
+
const ann = annotations.fields.get(f.name);
|
|
75
|
+
return f.type === 'String' && !ann?.hidden && !ann?.tenantKey && !f.isId;
|
|
76
|
+
});
|
|
77
|
+
// ── Tool Definition ──────────────────────────────────
|
|
78
|
+
lines.push(`export const ${prismaModel}Tools = defineTool<PrismaVurbContext>('db_${snakeName}', {`);
|
|
79
|
+
lines.push(` actions: {`);
|
|
80
|
+
// ── find_many ─────────────────────────────────────────
|
|
81
|
+
emitFindMany(lines, model, annotations, prismaModel, filterableFields);
|
|
82
|
+
// ── find_unique ───────────────────────────────────────
|
|
83
|
+
emitFindUnique(lines, annotations, prismaModel, idName, idZod);
|
|
84
|
+
// ── create ────────────────────────────────────────────
|
|
85
|
+
emitCreate(lines, annotations, prismaModel, createFields);
|
|
86
|
+
// ── update ────────────────────────────────────────────
|
|
87
|
+
emitUpdate(lines, annotations, prismaModel, idName, idZod, createFields);
|
|
88
|
+
// ── delete ────────────────────────────────────────────
|
|
89
|
+
emitDelete(lines, annotations, prismaModel, idName, idZod);
|
|
90
|
+
lines.push(` },`);
|
|
91
|
+
lines.push(`});`);
|
|
92
|
+
lines.push(``);
|
|
93
|
+
return {
|
|
94
|
+
path: `${prismaModel}Tools.ts`,
|
|
95
|
+
content: lines.join('\n'),
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
// ── Context Type Emitter ─────────────────────────────────
|
|
99
|
+
function emitContextType(lines, annotations) {
|
|
100
|
+
lines.push(`// ── Context Contract (Shift-Left Security) ──────────────`);
|
|
101
|
+
lines.push(`//`);
|
|
102
|
+
lines.push(`// If the developer forgets to provide these in contextFactory,`);
|
|
103
|
+
lines.push(`// TypeScript compilation fails — not runtime.`);
|
|
104
|
+
lines.push(``);
|
|
105
|
+
lines.push(`export interface PrismaVurbContext {`);
|
|
106
|
+
lines.push(` readonly prisma: { [model: string]: any };`);
|
|
107
|
+
if (annotations.tenantKeyField) {
|
|
108
|
+
lines.push(` /** Tenant isolation key — injected into every query WHERE clause */`);
|
|
109
|
+
lines.push(` readonly ${annotations.tenantKeyField}: string;`);
|
|
110
|
+
}
|
|
111
|
+
lines.push(`}`);
|
|
112
|
+
lines.push(``);
|
|
113
|
+
}
|
|
114
|
+
// ── Action Emitters ──────────────────────────────────────
|
|
115
|
+
function emitFindMany(lines, model, annotations, prismaModel, filterableFields) {
|
|
116
|
+
lines.push(` find_many: {`);
|
|
117
|
+
lines.push(` readOnly: true,`);
|
|
118
|
+
lines.push(` description: 'List ${model.name} records with pagination',`);
|
|
119
|
+
lines.push(` returns: ${toPascalCase(model.name)}Presenter,`);
|
|
120
|
+
lines.push(` params: z.object({`);
|
|
121
|
+
// Filterable string fields → contains filter
|
|
122
|
+
for (const f of filterableFields) {
|
|
123
|
+
const ann = annotations.fields.get(f.name);
|
|
124
|
+
const desc = ann?.description ? `.describe('Filter by ${f.name}')` : '';
|
|
125
|
+
lines.push(` ${f.name}_contains: z.string()${desc}.optional(),`);
|
|
126
|
+
}
|
|
127
|
+
// Pagination — OOM protection
|
|
128
|
+
lines.push(` take: z.number().int().min(1).max(50).default(20).describe('Max rows per page (capped at 50)'),`);
|
|
129
|
+
lines.push(` skip: z.number().int().min(0).default(0).describe('Offset for pagination'),`);
|
|
130
|
+
lines.push(` }),`);
|
|
131
|
+
lines.push(` handler: async (ctx, args) => {`);
|
|
132
|
+
// Build WHERE clause
|
|
133
|
+
lines.push(` const where: Record<string, unknown> = {};`);
|
|
134
|
+
// Tenant isolation
|
|
135
|
+
if (annotations.tenantKeyField) {
|
|
136
|
+
lines.push(` where['${annotations.tenantKeyField}'] = ctx.${annotations.tenantKeyField};`);
|
|
137
|
+
}
|
|
138
|
+
// Filters
|
|
139
|
+
for (const f of filterableFields) {
|
|
140
|
+
lines.push(` if (args.${f.name}_contains !== undefined) {`);
|
|
141
|
+
lines.push(` where['${f.name}'] = { contains: args.${f.name}_contains };`);
|
|
142
|
+
lines.push(` }`);
|
|
143
|
+
}
|
|
144
|
+
lines.push(` return await ctx.prisma.${prismaModel}.findMany({`);
|
|
145
|
+
lines.push(` where,`);
|
|
146
|
+
lines.push(` take: args.take,`);
|
|
147
|
+
lines.push(` skip: args.skip,`);
|
|
148
|
+
lines.push(` });`);
|
|
149
|
+
lines.push(` },`);
|
|
150
|
+
lines.push(` },`);
|
|
151
|
+
}
|
|
152
|
+
function emitFindUnique(lines, annotations, prismaModel, idName, idZod) {
|
|
153
|
+
lines.push(` find_unique: {`);
|
|
154
|
+
lines.push(` readOnly: true,`);
|
|
155
|
+
lines.push(` description: 'Get a single record by ID',`);
|
|
156
|
+
lines.push(` returns: ${toPascalCase(prismaModel)}Presenter,`);
|
|
157
|
+
lines.push(` params: z.object({`);
|
|
158
|
+
lines.push(` ${idName}: ${idZod},`);
|
|
159
|
+
lines.push(` }),`);
|
|
160
|
+
lines.push(` handler: async (ctx, args) => {`);
|
|
161
|
+
// WHERE with tenant isolation
|
|
162
|
+
if (annotations.tenantKeyField) {
|
|
163
|
+
lines.push(` const result = await ctx.prisma.${prismaModel}.findUnique({`);
|
|
164
|
+
lines.push(` where: { ${idName}: args.${idName}, ${annotations.tenantKeyField}: ctx.${annotations.tenantKeyField} },`);
|
|
165
|
+
lines.push(` });`);
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
lines.push(` const result = await ctx.prisma.${prismaModel}.findUnique({`);
|
|
169
|
+
lines.push(` where: { ${idName}: args.${idName} },`);
|
|
170
|
+
lines.push(` });`);
|
|
171
|
+
}
|
|
172
|
+
lines.push(` if (!result) return { content: [{ type: 'text', text: '${toPascalCase(prismaModel)} not found' }], isError: true };`);
|
|
173
|
+
lines.push(` return result;`);
|
|
174
|
+
lines.push(` },`);
|
|
175
|
+
lines.push(` },`);
|
|
176
|
+
}
|
|
177
|
+
function emitCreate(lines, annotations, prismaModel, createFields) {
|
|
178
|
+
lines.push(` create: {`);
|
|
179
|
+
lines.push(` description: 'Create a new record',`);
|
|
180
|
+
lines.push(` returns: ${toPascalCase(prismaModel)}Presenter,`);
|
|
181
|
+
lines.push(` params: z.object({`);
|
|
182
|
+
for (const field of createFields) {
|
|
183
|
+
const ann = annotations.fields.get(field.name);
|
|
184
|
+
let zodExpr = mapScalarType(field.type);
|
|
185
|
+
if (ann?.description) {
|
|
186
|
+
zodExpr = `${zodExpr}.describe('${ann.description.replace(/'/g, "\\'")}')`;
|
|
187
|
+
}
|
|
188
|
+
// Optional fields stay optional in create
|
|
189
|
+
if (!field.isRequired || field.hasDefaultValue) {
|
|
190
|
+
zodExpr = `${zodExpr}.optional()`;
|
|
191
|
+
}
|
|
192
|
+
lines.push(` ${field.name}: ${zodExpr},`);
|
|
193
|
+
}
|
|
194
|
+
lines.push(` }),`);
|
|
195
|
+
lines.push(` handler: async (ctx, args) => {`);
|
|
196
|
+
if (annotations.tenantKeyField) {
|
|
197
|
+
lines.push(` return await ctx.prisma.${prismaModel}.create({`);
|
|
198
|
+
lines.push(` data: { ...args, ${annotations.tenantKeyField}: ctx.${annotations.tenantKeyField} },`);
|
|
199
|
+
lines.push(` });`);
|
|
200
|
+
}
|
|
201
|
+
else {
|
|
202
|
+
lines.push(` return await ctx.prisma.${prismaModel}.create({`);
|
|
203
|
+
lines.push(` data: args,`);
|
|
204
|
+
lines.push(` });`);
|
|
205
|
+
}
|
|
206
|
+
lines.push(` },`);
|
|
207
|
+
lines.push(` },`);
|
|
208
|
+
}
|
|
209
|
+
function emitUpdate(lines, annotations, prismaModel, idName, idZod, createFields) {
|
|
210
|
+
lines.push(` update: {`);
|
|
211
|
+
lines.push(` description: 'Update an existing record',`);
|
|
212
|
+
lines.push(` returns: ${toPascalCase(prismaModel)}Presenter,`);
|
|
213
|
+
lines.push(` params: z.object({`);
|
|
214
|
+
lines.push(` ${idName}: ${idZod},`);
|
|
215
|
+
// All create fields as .optional() for partial update
|
|
216
|
+
for (const field of createFields) {
|
|
217
|
+
if (field.name === idName)
|
|
218
|
+
continue; // Skip ID, already added
|
|
219
|
+
const ann = annotations.fields.get(field.name);
|
|
220
|
+
let zodExpr = mapScalarType(field.type);
|
|
221
|
+
if (ann?.description) {
|
|
222
|
+
zodExpr = `${zodExpr}.describe('${ann.description.replace(/'/g, "\\'")}')`;
|
|
223
|
+
}
|
|
224
|
+
lines.push(` ${field.name}: ${zodExpr}.optional(),`);
|
|
225
|
+
}
|
|
226
|
+
lines.push(` }),`);
|
|
227
|
+
lines.push(` handler: async (ctx, args) => {`);
|
|
228
|
+
lines.push(` const { ${idName}, ...data } = args;`);
|
|
229
|
+
if (annotations.tenantKeyField) {
|
|
230
|
+
lines.push(` return await ctx.prisma.${prismaModel}.update({`);
|
|
231
|
+
lines.push(` where: { ${idName}, ${annotations.tenantKeyField}: ctx.${annotations.tenantKeyField} },`);
|
|
232
|
+
lines.push(` data,`);
|
|
233
|
+
lines.push(` });`);
|
|
234
|
+
}
|
|
235
|
+
else {
|
|
236
|
+
lines.push(` return await ctx.prisma.${prismaModel}.update({`);
|
|
237
|
+
lines.push(` where: { ${idName} },`);
|
|
238
|
+
lines.push(` data,`);
|
|
239
|
+
lines.push(` });`);
|
|
240
|
+
}
|
|
241
|
+
lines.push(` },`);
|
|
242
|
+
lines.push(` },`);
|
|
243
|
+
}
|
|
244
|
+
function emitDelete(lines, annotations, prismaModel, idName, idZod) {
|
|
245
|
+
lines.push(` delete: {`);
|
|
246
|
+
lines.push(` destructive: true,`);
|
|
247
|
+
lines.push(` description: 'Delete a record by ID',`);
|
|
248
|
+
lines.push(` params: z.object({`);
|
|
249
|
+
lines.push(` ${idName}: ${idZod},`);
|
|
250
|
+
lines.push(` }),`);
|
|
251
|
+
lines.push(` handler: async (ctx, args) => {`);
|
|
252
|
+
if (annotations.tenantKeyField) {
|
|
253
|
+
lines.push(` await ctx.prisma.${prismaModel}.delete({`);
|
|
254
|
+
lines.push(` where: { ${idName}: args.${idName}, ${annotations.tenantKeyField}: ctx.${annotations.tenantKeyField} },`);
|
|
255
|
+
lines.push(` });`);
|
|
256
|
+
}
|
|
257
|
+
else {
|
|
258
|
+
lines.push(` await ctx.prisma.${prismaModel}.delete({`);
|
|
259
|
+
lines.push(` where: { ${idName}: args.${idName} },`);
|
|
260
|
+
lines.push(` });`);
|
|
261
|
+
}
|
|
262
|
+
lines.push(` return { deleted: true };`);
|
|
263
|
+
lines.push(` },`);
|
|
264
|
+
lines.push(` },`);
|
|
265
|
+
}
|
|
266
|
+
//# sourceMappingURL=ToolEmitter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ToolEmitter.js","sourceRoot":"","sources":["../../src/emitter/ToolEmitter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../src/generator.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Prisma Generator Entry Point — vurb-prisma-gen
|
|
4
|
+
*
|
|
5
|
+
* Intercepts `npx prisma generate` and emits Vurb Presenters
|
|
6
|
+
* and ToolBuilders with field-level security, tenant isolation, and
|
|
7
|
+
* OOM protection.
|
|
8
|
+
*
|
|
9
|
+
* Usage in schema.prisma:
|
|
10
|
+
* ```prisma
|
|
11
|
+
* generator mcp {
|
|
12
|
+
* provider = "vurb-prisma-gen"
|
|
13
|
+
* output = "../src/tools/database"
|
|
14
|
+
* }
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* @module
|
|
18
|
+
*/
|
|
19
|
+
import { generatorHandler } from '@prisma/generator-helper';
|
|
20
|
+
import { writeFileSync, mkdirSync } from 'node:fs';
|
|
21
|
+
import { join, resolve } from 'node:path';
|
|
22
|
+
import { parseAnnotations } from './parser/AnnotationParser.js';
|
|
23
|
+
import { emitPresenter } from './emitter/PresenterEmitter.js';
|
|
24
|
+
import { emitTool } from './emitter/ToolEmitter.js';
|
|
25
|
+
// ── Generator Handler ────────────────────────────────────
|
|
26
|
+
generatorHandler({
|
|
27
|
+
onManifest() {
|
|
28
|
+
return {
|
|
29
|
+
prettyName: 'Vurb Prisma Generator',
|
|
30
|
+
defaultOutput: './generated',
|
|
31
|
+
};
|
|
32
|
+
},
|
|
33
|
+
async onGenerate(options) {
|
|
34
|
+
const outputDir = resolve(options.generator.output?.value ?? './generated');
|
|
35
|
+
mkdirSync(outputDir, { recursive: true });
|
|
36
|
+
const models = options.dmmf.datamodel.models;
|
|
37
|
+
const generatedNames = [];
|
|
38
|
+
for (const model of models) {
|
|
39
|
+
const annotations = parseAnnotations(model);
|
|
40
|
+
// Emit Presenter (MVA View Layer — Egress Firewall)
|
|
41
|
+
const presenterFile = emitPresenter(model, annotations);
|
|
42
|
+
const presenterPath = join(outputDir, presenterFile.path);
|
|
43
|
+
writeFileSync(presenterPath, presenterFile.content, 'utf-8');
|
|
44
|
+
// Emit Tool (MVA Agent Layer — CRUD with tenant isolation)
|
|
45
|
+
const toolFile = emitTool(model, annotations);
|
|
46
|
+
const toolPath = join(outputDir, toolFile.path);
|
|
47
|
+
writeFileSync(toolPath, toolFile.content, 'utf-8');
|
|
48
|
+
generatedNames.push(model.name);
|
|
49
|
+
console.log(` 📄 ${presenterFile.path}`);
|
|
50
|
+
console.log(` 📄 ${toolFile.path}`);
|
|
51
|
+
}
|
|
52
|
+
// Emit barrel index.ts
|
|
53
|
+
const barrelFile = emitBarrel(generatedNames);
|
|
54
|
+
const barrelPath = join(outputDir, barrelFile.path);
|
|
55
|
+
writeFileSync(barrelPath, barrelFile.content, 'utf-8');
|
|
56
|
+
console.log(` 📄 ${barrelFile.path}`);
|
|
57
|
+
console.log(`\n🎉 Generated ${models.length * 2 + 1} files in ${outputDir}`);
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
// ── Barrel Emitter ───────────────────────────────────────
|
|
61
|
+
function emitBarrel(modelNames) {
|
|
62
|
+
const lines = [];
|
|
63
|
+
lines.push(`/**`);
|
|
64
|
+
lines.push(` * Generated barrel export — vurb-prisma-gen`);
|
|
65
|
+
lines.push(` * @generated`);
|
|
66
|
+
lines.push(` */`);
|
|
67
|
+
let isFirst = true;
|
|
68
|
+
for (const name of modelNames) {
|
|
69
|
+
const prismaModel = name.charAt(0).toLowerCase() + name.slice(1);
|
|
70
|
+
lines.push(`export { ${name}Presenter, ${name}ResponseSchema } from './${prismaModel}Presenter.js';`);
|
|
71
|
+
lines.push(`export { ${prismaModel}Tools } from './${prismaModel}Tools.js';`);
|
|
72
|
+
// Export PrismaVurbContext only from the first model to avoid duplicate identifiers
|
|
73
|
+
if (isFirst) {
|
|
74
|
+
lines.push(`export type { PrismaVurbContext } from './${prismaModel}Tools.js';`);
|
|
75
|
+
isFirst = false;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
lines.push(``);
|
|
79
|
+
return { path: 'index.ts', content: lines.join('\n') };
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=generator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generator.js","sourceRoot":"","sources":["../src/generator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NamingHelpers — Case conversion and pluralization utilities
|
|
3
|
+
*
|
|
4
|
+
* Reuses patterns from openapi-gen's TemplateHelpers.
|
|
5
|
+
*
|
|
6
|
+
* @module
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Convert PascalCase or camelCase to snake_case.
|
|
10
|
+
* @example toSnakeCase('UserProfile') → 'user_profile'
|
|
11
|
+
*/
|
|
12
|
+
export declare function toSnakeCase(str: string): string;
|
|
13
|
+
/**
|
|
14
|
+
* Ensure PascalCase.
|
|
15
|
+
* @example toPascalCase('user_profile') → 'UserProfile'
|
|
16
|
+
*/
|
|
17
|
+
export declare function toPascalCase(str: string): string;
|
|
18
|
+
/**
|
|
19
|
+
* Simple English pluralize (covers common cases).
|
|
20
|
+
* @example pluralize('User') → 'Users'
|
|
21
|
+
* @example pluralize('Company') → 'Companies'
|
|
22
|
+
*/
|
|
23
|
+
export declare function pluralize(str: string): string;
|
|
24
|
+
//# sourceMappingURL=NamingHelpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NamingHelpers.d.ts","sourceRoot":"","sources":["../../src/helpers/NamingHelpers.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH;;;GAGG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAK/C;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAGhD;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAS7C"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NamingHelpers — Case conversion and pluralization utilities
|
|
3
|
+
*
|
|
4
|
+
* Reuses patterns from openapi-gen's TemplateHelpers.
|
|
5
|
+
*
|
|
6
|
+
* @module
|
|
7
|
+
*/
|
|
8
|
+
// ── Case Conversion ──────────────────────────────────────
|
|
9
|
+
/**
|
|
10
|
+
* Convert PascalCase or camelCase to snake_case.
|
|
11
|
+
* @example toSnakeCase('UserProfile') → 'user_profile'
|
|
12
|
+
*/
|
|
13
|
+
export function toSnakeCase(str) {
|
|
14
|
+
return str
|
|
15
|
+
.replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2')
|
|
16
|
+
.replace(/([a-z\d])([A-Z])/g, '$1_$2')
|
|
17
|
+
.toLowerCase();
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Ensure PascalCase.
|
|
21
|
+
* @example toPascalCase('user_profile') → 'UserProfile'
|
|
22
|
+
*/
|
|
23
|
+
export function toPascalCase(str) {
|
|
24
|
+
return str
|
|
25
|
+
.replace(/(^|_)([a-z])/g, (_m, _p, c) => c.toUpperCase());
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Simple English pluralize (covers common cases).
|
|
29
|
+
* @example pluralize('User') → 'Users'
|
|
30
|
+
* @example pluralize('Company') → 'Companies'
|
|
31
|
+
*/
|
|
32
|
+
export function pluralize(str) {
|
|
33
|
+
if (str.endsWith('s') || str.endsWith('x') || str.endsWith('z')
|
|
34
|
+
|| str.endsWith('sh') || str.endsWith('ch')) {
|
|
35
|
+
return str + 'es';
|
|
36
|
+
}
|
|
37
|
+
if (str.endsWith('y') && !/[aeiou]y$/i.test(str)) {
|
|
38
|
+
return str.slice(0, -1) + 'ies';
|
|
39
|
+
}
|
|
40
|
+
return str + 's';
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=NamingHelpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NamingHelpers.js","sourceRoot":"","sources":["../../src/helpers/NamingHelpers.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,4DAA4D;AAE5D;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,GAAW;IACnC,OAAO,GAAG;SACL,OAAO,CAAC,uBAAuB,EAAE,OAAO,CAAC;SACzC,OAAO,CAAC,mBAAmB,EAAE,OAAO,CAAC;SACrC,WAAW,EAAE,CAAC;AACvB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,GAAW;IACpC,OAAO,GAAG;SACL,OAAO,CAAC,eAAe,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;AAC1E,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,SAAS,CAAC,GAAW;IACjC,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC;WACxD,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QAC9C,OAAO,GAAG,GAAG,IAAI,CAAC;IACtB,CAAC;IACD,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QAC/C,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC;IACpC,CAAC;IACD,OAAO,GAAG,GAAG,GAAG,CAAC;AACrB,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @vinkius-core/prisma-gen — Root Barrel Export
|
|
3
|
+
*
|
|
4
|
+
* Public API for programmatic usage.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```typescript
|
|
8
|
+
* import { parseAnnotations, emitPresenter, emitTool } from '@vurb/prisma-gen';
|
|
9
|
+
* ```
|
|
10
|
+
*
|
|
11
|
+
* @module
|
|
12
|
+
*/
|
|
13
|
+
export { parseAnnotations } from './parser/AnnotationParser.js';
|
|
14
|
+
export type { FieldAnnotation, ModelAnnotations, DMMFField, DMMFModel, } from './parser/AnnotationParser.js';
|
|
15
|
+
export { emitPresenter } from './emitter/PresenterEmitter.js';
|
|
16
|
+
export { emitTool } from './emitter/ToolEmitter.js';
|
|
17
|
+
export type { GeneratedFile } from './types.js';
|
|
18
|
+
export { toSnakeCase, toPascalCase, pluralize } from './helpers/NamingHelpers.js';
|
|
19
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAChE,YAAY,EACR,eAAe,EAAE,gBAAgB,EACjC,SAAS,EAAE,SAAS,GACvB,MAAM,8BAA8B,CAAC;AAGtC,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACpD,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAGhD,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @vinkius-core/prisma-gen — Root Barrel Export
|
|
3
|
+
*
|
|
4
|
+
* Public API for programmatic usage.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```typescript
|
|
8
|
+
* import { parseAnnotations, emitPresenter, emitTool } from '@vurb/prisma-gen';
|
|
9
|
+
* ```
|
|
10
|
+
*
|
|
11
|
+
* @module
|
|
12
|
+
*/
|
|
13
|
+
// ── Parser ───────────────────────────────────────────────
|
|
14
|
+
export { parseAnnotations } from './parser/AnnotationParser.js';
|
|
15
|
+
// ── Emitters ─────────────────────────────────────────────
|
|
16
|
+
export { emitPresenter } from './emitter/PresenterEmitter.js';
|
|
17
|
+
export { emitTool } from './emitter/ToolEmitter.js';
|
|
18
|
+
// ── Helpers ──────────────────────────────────────────────
|
|
19
|
+
export { toSnakeCase, toPascalCase, pluralize } from './helpers/NamingHelpers.js';
|
|
20
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,4DAA4D;AAC5D,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAMhE,4DAA4D;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAGpD,4DAA4D;AAC5D,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AnnotationParser — Extracts @vurb.* annotations from Prisma DMMF
|
|
3
|
+
*
|
|
4
|
+
* Reads the `documentation` field (/// triple-comments) from each Prisma
|
|
5
|
+
* model field and extracts Vurb security annotations.
|
|
6
|
+
*
|
|
7
|
+
* IMPORTANT: Prisma DMMF concatenates multi-line comments with \n.
|
|
8
|
+
* We use `includes()` for boolean flags (not anchored regex)
|
|
9
|
+
* to handle cases like "User's password.\n@vurb.hide".
|
|
10
|
+
*
|
|
11
|
+
* @module
|
|
12
|
+
*/
|
|
13
|
+
/** Parsed annotations for a single field */
|
|
14
|
+
export interface FieldAnnotation {
|
|
15
|
+
/** Field is excluded from the Response Zod schema (Egress Firewall) */
|
|
16
|
+
readonly hidden: boolean;
|
|
17
|
+
/** LLM-facing description injected via .describe() */
|
|
18
|
+
readonly description?: string;
|
|
19
|
+
/** Field used for tenant isolation in WHERE clauses */
|
|
20
|
+
readonly tenantKey: boolean;
|
|
21
|
+
}
|
|
22
|
+
/** Parsed annotations for an entire model */
|
|
23
|
+
export interface ModelAnnotations {
|
|
24
|
+
/** Per-field annotation map (field name → annotations) */
|
|
25
|
+
readonly fields: Map<string, FieldAnnotation>;
|
|
26
|
+
/** The field name marked as @vurb.tenantKey (at most one per model) */
|
|
27
|
+
readonly tenantKeyField?: string;
|
|
28
|
+
}
|
|
29
|
+
/** Minimal Prisma DMMF field shape */
|
|
30
|
+
export interface DMMFField {
|
|
31
|
+
readonly name: string;
|
|
32
|
+
readonly kind: string;
|
|
33
|
+
readonly type: string;
|
|
34
|
+
readonly isList: boolean;
|
|
35
|
+
readonly isRequired: boolean;
|
|
36
|
+
readonly isId: boolean;
|
|
37
|
+
readonly hasDefaultValue: boolean;
|
|
38
|
+
readonly isUnique: boolean;
|
|
39
|
+
readonly documentation?: string;
|
|
40
|
+
}
|
|
41
|
+
/** Minimal Prisma DMMF model shape */
|
|
42
|
+
export interface DMMFModel {
|
|
43
|
+
readonly name: string;
|
|
44
|
+
readonly fields: readonly DMMFField[];
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Parse all @vurb.* annotations from a Prisma DMMF model.
|
|
48
|
+
*
|
|
49
|
+
* @param model - Prisma DMMF model
|
|
50
|
+
* @returns Parsed annotations with field map and tenant key
|
|
51
|
+
*/
|
|
52
|
+
export declare function parseAnnotations(model: DMMFModel): ModelAnnotations;
|
|
53
|
+
//# sourceMappingURL=AnnotationParser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AnnotationParser.d.ts","sourceRoot":"","sources":["../../src/parser/AnnotationParser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,4CAA4C;AAC5C,MAAM,WAAW,eAAe;IAC5B,uEAAuE;IACvE,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,sDAAsD;IACtD,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,uDAAuD;IACvD,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;CAC/B;AAED,6CAA6C;AAC7C,MAAM,WAAW,gBAAgB;IAC7B,0DAA0D;IAC1D,QAAQ,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IAC9C,uEAAuE;IACvE,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;CACpC;AAID,sCAAsC;AACtC,MAAM,WAAW,SAAS;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAC;IAClC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;CACnC;AAED,sCAAsC;AACtC,MAAM,WAAW,SAAS;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,SAAS,SAAS,EAAE,CAAC;CACzC;AAUD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,SAAS,GAAG,gBAAgB,CA8BnE"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AnnotationParser — Extracts @vurb.* annotations from Prisma DMMF
|
|
3
|
+
*
|
|
4
|
+
* Reads the `documentation` field (/// triple-comments) from each Prisma
|
|
5
|
+
* model field and extracts Vurb security annotations.
|
|
6
|
+
*
|
|
7
|
+
* IMPORTANT: Prisma DMMF concatenates multi-line comments with \n.
|
|
8
|
+
* We use `includes()` for boolean flags (not anchored regex)
|
|
9
|
+
* to handle cases like "User's password.\n@vurb.hide".
|
|
10
|
+
*
|
|
11
|
+
* @module
|
|
12
|
+
*/
|
|
13
|
+
// ── Constants ────────────────────────────────────────────
|
|
14
|
+
const VURB_HIDE = '@vurb.hide';
|
|
15
|
+
const VURB_TENANT_KEY = '@vurb.tenantKey';
|
|
16
|
+
const VURB_DESCRIBE_REGEX = /@vurb\.describe\("([^"]+)"\)/;
|
|
17
|
+
// ── Public API ───────────────────────────────────────────
|
|
18
|
+
/**
|
|
19
|
+
* Parse all @vurb.* annotations from a Prisma DMMF model.
|
|
20
|
+
*
|
|
21
|
+
* @param model - Prisma DMMF model
|
|
22
|
+
* @returns Parsed annotations with field map and tenant key
|
|
23
|
+
*/
|
|
24
|
+
export function parseAnnotations(model) {
|
|
25
|
+
const fields = new Map();
|
|
26
|
+
let tenantKeyField;
|
|
27
|
+
for (const field of model.fields) {
|
|
28
|
+
const doc = field.documentation ?? '';
|
|
29
|
+
// Boolean flags — simple includes(), no anchored regex
|
|
30
|
+
// Handles multi-line docs like "User's password.\n@vurb.hide"
|
|
31
|
+
const hidden = doc.includes(VURB_HIDE);
|
|
32
|
+
const tenantKey = doc.includes(VURB_TENANT_KEY);
|
|
33
|
+
// String extraction — non-anchored regex
|
|
34
|
+
const describeMatch = doc.match(VURB_DESCRIBE_REGEX);
|
|
35
|
+
const description = describeMatch?.[1];
|
|
36
|
+
if (tenantKey) {
|
|
37
|
+
tenantKeyField = field.name;
|
|
38
|
+
}
|
|
39
|
+
const annotation = description !== undefined
|
|
40
|
+
? { hidden, description, tenantKey }
|
|
41
|
+
: { hidden, tenantKey };
|
|
42
|
+
fields.set(field.name, annotation);
|
|
43
|
+
}
|
|
44
|
+
const result = tenantKeyField !== undefined
|
|
45
|
+
? { fields, tenantKeyField }
|
|
46
|
+
: { fields };
|
|
47
|
+
return result;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=AnnotationParser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AnnotationParser.js","sourceRoot":"","sources":["../../src/parser/AnnotationParser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AA2CH,4DAA4D;AAE5D,MAAM,SAAS,GAAG,YAAY,CAAC;AAC/B,MAAM,eAAe,GAAG,iBAAiB,CAAC;AAC1C,MAAM,mBAAmB,GAAG,8BAA8B,CAAC;AAE3D,4DAA4D;AAE5D;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAgB;IAC7C,MAAM,MAAM,GAAG,IAAI,GAAG,EAA2B,CAAC;IAClD,IAAI,cAAkC,CAAC;IAEvC,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;QAC/B,MAAM,GAAG,GAAG,KAAK,CAAC,aAAa,IAAI,EAAE,CAAC;QAEtC,uDAAuD;QACvD,8DAA8D;QAC9D,MAAM,MAAM,GAAG,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;QACvC,MAAM,SAAS,GAAG,GAAG,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC;QAEhD,yCAAyC;QACzC,MAAM,aAAa,GAAG,GAAG,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;QACrD,MAAM,WAAW,GAAG,aAAa,EAAE,CAAC,CAAC,CAAC,CAAC;QAEvC,IAAI,SAAS,EAAE,CAAC;YACZ,cAAc,GAAG,KAAK,CAAC,IAAI,CAAC;QAChC,CAAC;QAED,MAAM,UAAU,GAAoB,WAAW,KAAK,SAAS;YACzD,CAAC,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE;YACpC,CAAC,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;QAC5B,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;IACvC,CAAC;IAED,MAAM,MAAM,GAAqB,cAAc,KAAK,SAAS;QACzD,CAAC,CAAC,EAAE,MAAM,EAAE,cAAc,EAAE;QAC5B,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,OAAO,MAAM,CAAC;AAClB,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,iDAAiD;AACjD,MAAM,WAAW,aAAa;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC5B"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|
package/package.json
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@vurb/prisma-gen",
|
|
3
|
+
"version": "3.1.31",
|
|
4
|
+
"description": "Prisma Generator for Vurb. Reads schema annotations (@vurb.hide, @vurb.describe, @vurb.tenantKey) and emits hardened Presenters and ToolBuilders with field-level security, tenant isolation, and OOM protection.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"bin": {
|
|
9
|
+
"vurb-prisma-gen": "./dist/generator.js"
|
|
10
|
+
},
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"import": "./dist/index.js",
|
|
14
|
+
"types": "./dist/index.d.ts"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "tsc",
|
|
19
|
+
"test": "vitest run",
|
|
20
|
+
"prepublishOnly": "npm run build"
|
|
21
|
+
},
|
|
22
|
+
"keywords": [
|
|
23
|
+
"mcp",
|
|
24
|
+
"prisma",
|
|
25
|
+
"generator",
|
|
26
|
+
"vurb",
|
|
27
|
+
"zod",
|
|
28
|
+
"mva",
|
|
29
|
+
"presenter",
|
|
30
|
+
"ai",
|
|
31
|
+
"llm",
|
|
32
|
+
"tenant-isolation",
|
|
33
|
+
"code-generator"
|
|
34
|
+
],
|
|
35
|
+
"author": "Renato Marinho",
|
|
36
|
+
"repository": {
|
|
37
|
+
"type": "git",
|
|
38
|
+
"url": "git+https://github.com/vinkius-labs/vurb.ts.git",
|
|
39
|
+
"directory": "packages/prisma-gen"
|
|
40
|
+
},
|
|
41
|
+
"bugs": {
|
|
42
|
+
"url": "https://github.com/vinkius-labs/vurb.ts/issues"
|
|
43
|
+
},
|
|
44
|
+
"homepage": "https://vurb.vinkius.com/",
|
|
45
|
+
"files": [
|
|
46
|
+
"dist",
|
|
47
|
+
"README.md"
|
|
48
|
+
],
|
|
49
|
+
"engines": {
|
|
50
|
+
"node": ">=18.0.0"
|
|
51
|
+
},
|
|
52
|
+
"publishConfig": {
|
|
53
|
+
"access": "public"
|
|
54
|
+
},
|
|
55
|
+
"dependencies": {
|
|
56
|
+
"@prisma/generator-helper": "^6.0.0"
|
|
57
|
+
},
|
|
58
|
+
"peerDependencies": {
|
|
59
|
+
"@vurb/core": "^3.0.0",
|
|
60
|
+
"zod": "^3.25.1 || ^4.0.0"
|
|
61
|
+
},
|
|
62
|
+
"devDependencies": {
|
|
63
|
+
"@types/node": "^25.3.0",
|
|
64
|
+
"@vurb/core": ">=3.0.0"
|
|
65
|
+
},
|
|
66
|
+
"license": "Apache-2.0"
|
|
67
|
+
}
|