@innovixx/prisma-typed-json-generator 0.0.1
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/LICENSE +21 -0
- package/README.md +58 -0
- package/dist/bin/index.js +3 -0
- package/dist/bin/index.js.map +1 -0
- package/dist/index.js +131 -0
- package/dist/index.js.map +1 -0
- package/dist/utils/getEnum/index.js +5 -0
- package/dist/utils/getEnum/index.js.map +1 -0
- package/package.json +27 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) Innovixx Digital Limited
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# prisma-typed-json-generator
|
|
2
|
+
|
|
3
|
+
A Prisma generator that automatically creates TypeScript types for your `Json` fields with `@type()` annotations, and patches the generated Prisma Client types to use your custom types.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
- Extracts custom types from commented blocks in your Prisma schema.
|
|
7
|
+
- Generates a `prisma-json.types.ts` file in your Prisma Client output directory.
|
|
8
|
+
- Patches the generated `index.d.ts` to use your custom types for annotated `Json` fields, using a namespace import to avoid type name clashes.
|
|
9
|
+
- Context-aware: only patches the correct field in the correct model, even if multiple models use the same field name.
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
1. Add the generator to your `schema.prisma`:
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
generator client {
|
|
17
|
+
provider = "prisma-client-js"
|
|
18
|
+
output = "./client"
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
generator prisma_types_json_generator {
|
|
22
|
+
provider = "prisma-typed-json-generator"
|
|
23
|
+
output = "../types"
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
2. Annotate your `Json` fields with `@type()` and define your types in comments:
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
// type Address {
|
|
31
|
+
// street string
|
|
32
|
+
// city string
|
|
33
|
+
// country string
|
|
34
|
+
// }
|
|
35
|
+
|
|
36
|
+
model User {
|
|
37
|
+
id Int @id @default(autoincrement())
|
|
38
|
+
email String @unique
|
|
39
|
+
name String?
|
|
40
|
+
address Json // @type(Address)
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
3. Run `prisma generate`:
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
npx prisma generate
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
4. The generator will:
|
|
51
|
+
- Create `prisma-json.types.ts` in your client output directory.
|
|
52
|
+
- Patch `index.d.ts` to use `PrismaJsonTypes.Address` for the `address` field in the `User` model.
|
|
53
|
+
|
|
54
|
+
## Why?
|
|
55
|
+
Prisma's `Json` fields are typed as `Prisma.JsonValue` by default, which is not type-safe. This generator lets you use your own types for better safety and DX.
|
|
56
|
+
|
|
57
|
+
## License
|
|
58
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/bin/index.ts"],"names":[],"mappings":";AACA,OAAO,aAAa,CAAA","sourcesContent":["#!/usr/bin/env node\nimport '../index.js'\n"]}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
function extractJsonTypeAnnotations(schemaContent) {
|
|
2
|
+
const result = {};
|
|
3
|
+
const modelRegex = /model\s+([A-Za-z0-9_]+)\s*\{([\s\S]*?)\}/g;
|
|
4
|
+
let modelMatch;
|
|
5
|
+
while ((modelMatch = modelRegex.exec(schemaContent)) !== null) {
|
|
6
|
+
const modelName = modelMatch[1];
|
|
7
|
+
const body = modelMatch[2];
|
|
8
|
+
for (const line of body.split('\n')) {
|
|
9
|
+
const fieldMatch = /^\s*([A-Za-z0-9_]+)\s+Json.*@type\(([^)]+)\)/.exec(line);
|
|
10
|
+
if (fieldMatch) {
|
|
11
|
+
const fieldName = fieldMatch[1];
|
|
12
|
+
const typeName = fieldMatch[2];
|
|
13
|
+
result[`${modelName}.${fieldName}`] = typeName;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return result;
|
|
18
|
+
}
|
|
19
|
+
import generatorHelper from '@prisma/generator-helper';
|
|
20
|
+
import internals from '@prisma/internals';
|
|
21
|
+
import path from 'path';
|
|
22
|
+
import pkg from '../package.json' with { type: "json" };
|
|
23
|
+
import fs from 'fs';
|
|
24
|
+
export function extractCommentedTypes(schemaContent) {
|
|
25
|
+
const commentedTypeBlocks = [];
|
|
26
|
+
const typeBlockRegex = /\/\/\s*type\s+([A-Za-z0-9_]+)\s*\{([\s\S]*?)\}/g;
|
|
27
|
+
let match;
|
|
28
|
+
while ((match = typeBlockRegex.exec(schemaContent)) !== null) {
|
|
29
|
+
commentedTypeBlocks.push(match[0]);
|
|
30
|
+
}
|
|
31
|
+
const typeObjects = {};
|
|
32
|
+
for (const block of commentedTypeBlocks) {
|
|
33
|
+
const headerMatch = /type\s+([A-Za-z0-9_]+)\s*\{([\s\S]*?)\}/.exec(block);
|
|
34
|
+
if (!headerMatch)
|
|
35
|
+
continue;
|
|
36
|
+
const typeName = headerMatch[1];
|
|
37
|
+
const body = headerMatch[2];
|
|
38
|
+
const fields = {};
|
|
39
|
+
for (const line of body.split('\n')) {
|
|
40
|
+
const cleaned = line.replace(/^\s*\/\//, '').trim();
|
|
41
|
+
if (!cleaned)
|
|
42
|
+
continue;
|
|
43
|
+
const fieldMatch = /^([A-Za-z0-9_]+)\s+([A-Za-z0-9_\[\]?]+)$/.exec(cleaned);
|
|
44
|
+
if (fieldMatch) {
|
|
45
|
+
fields[fieldMatch[1]] = fieldMatch[2];
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
typeObjects[typeName] = fields;
|
|
49
|
+
}
|
|
50
|
+
return typeObjects;
|
|
51
|
+
}
|
|
52
|
+
export async function writeTypesFile(typeObjects, clientDir) {
|
|
53
|
+
let typeFileContent = '// This file is auto-generated by prisma-typed-json-generator\n\n';
|
|
54
|
+
for (const [typeName, fields] of Object.entries(typeObjects)) {
|
|
55
|
+
typeFileContent += `export type ${typeName} = {\n`;
|
|
56
|
+
for (const [field, type] of Object.entries(fields)) {
|
|
57
|
+
let tsType = type
|
|
58
|
+
.replace(/^string$/i, 'string')
|
|
59
|
+
.replace(/^int$/i, 'number')
|
|
60
|
+
.replace(/^float$/i, 'number')
|
|
61
|
+
.replace(/^boolean$/i, 'boolean')
|
|
62
|
+
.replace(/^json$/i, 'any')
|
|
63
|
+
.replace(/\?$/, ' | null')
|
|
64
|
+
.replace(/\[\]$/, '[]');
|
|
65
|
+
typeFileContent += ` ${field}: ${tsType};\n`;
|
|
66
|
+
}
|
|
67
|
+
typeFileContent += '}\n\n';
|
|
68
|
+
}
|
|
69
|
+
const outputPath = path.join(clientDir, 'prisma-json.types.ts');
|
|
70
|
+
await fs.promises.mkdir(clientDir, { recursive: true });
|
|
71
|
+
await fs.promises.writeFile(outputPath, typeFileContent, 'utf-8');
|
|
72
|
+
return outputPath;
|
|
73
|
+
}
|
|
74
|
+
const { generatorHandler } = generatorHelper;
|
|
75
|
+
const { logger } = internals;
|
|
76
|
+
generatorHandler({
|
|
77
|
+
onManifest() {
|
|
78
|
+
return {
|
|
79
|
+
version: pkg.version,
|
|
80
|
+
defaultOutput: '../generated',
|
|
81
|
+
prettyName: "prisma-typed-json-generator",
|
|
82
|
+
};
|
|
83
|
+
},
|
|
84
|
+
onGenerate: async (options) => {
|
|
85
|
+
logger.info(`prisma-typed-json-generator:Generating...`);
|
|
86
|
+
const schemaFileLocation = options.generator.sourceFilePath;
|
|
87
|
+
const clientGenerator = options.otherGenerators.find((g) => g.name === 'client');
|
|
88
|
+
if (!clientGenerator)
|
|
89
|
+
throw new Error('Prisma Client generator not found. Please ensure that generator Client is specified in your schema.');
|
|
90
|
+
const clientOutput = clientGenerator.output?.value;
|
|
91
|
+
const schemaContent = await fs.promises.readFile(schemaFileLocation, 'utf-8');
|
|
92
|
+
const typeObjects = extractCommentedTypes(schemaContent);
|
|
93
|
+
if (clientOutput) {
|
|
94
|
+
await writeTypesFile(typeObjects, clientOutput);
|
|
95
|
+
}
|
|
96
|
+
if (clientOutput) {
|
|
97
|
+
const indexDtsPath = path.join(clientOutput, 'index.d.ts');
|
|
98
|
+
let indexDtsContent = await fs.promises.readFile(indexDtsPath, 'utf-8');
|
|
99
|
+
let updated = false;
|
|
100
|
+
const jsonTypeAnnotations = extractJsonTypeAnnotations(schemaContent);
|
|
101
|
+
for (const [modelField, typeName] of Object.entries(jsonTypeAnnotations)) {
|
|
102
|
+
const [model, field] = modelField.split('.');
|
|
103
|
+
const payloadBlockRegex = new RegExp(`export type \\$${model}Payload<[^=]+=[^>]+> = {([\\s\\S]*?)}\\n`, 'g');
|
|
104
|
+
indexDtsContent = indexDtsContent.replace(payloadBlockRegex, (block) => {
|
|
105
|
+
const lines = block.split('\n');
|
|
106
|
+
let inScalars = false;
|
|
107
|
+
for (let i = 0; i < lines.length; i++) {
|
|
108
|
+
if (lines[i].includes('scalars: $Extensions.GetPayloadResult<{'))
|
|
109
|
+
inScalars = true;
|
|
110
|
+
if (inScalars && lines[i].includes(`${field}: Prisma.JsonValue`)) {
|
|
111
|
+
lines[i] = lines[i].replace('Prisma.JsonValue', `PrismaJsonTypes.${typeName}`);
|
|
112
|
+
updated = true;
|
|
113
|
+
}
|
|
114
|
+
if (inScalars && lines[i].includes('}, ExtArgs["result"]'))
|
|
115
|
+
inScalars = false;
|
|
116
|
+
}
|
|
117
|
+
return lines.join('\n');
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
if (updated) {
|
|
121
|
+
const importLine = `import * as PrismaJsonTypes from './prisma-json.types';`;
|
|
122
|
+
if (!indexDtsContent.includes(importLine)) {
|
|
123
|
+
indexDtsContent = indexDtsContent.replace(/(import .*?;\n)/, `$1${importLine}\n`);
|
|
124
|
+
}
|
|
125
|
+
await fs.promises.writeFile(indexDtsPath, indexDtsContent, 'utf-8');
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
logger.info(`prisma-typed-json-generator:Generating...Done`);
|
|
129
|
+
},
|
|
130
|
+
});
|
|
131
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["function extractJsonTypeAnnotations(schemaContent: string): Record<string, string> {\n\tconst result: Record<string, string> = {};\n\tconst modelRegex = /model\\s+([A-Za-z0-9_]+)\\s*\\{([\\s\\S]*?)\\}/g;\n\tlet modelMatch;\n\twhile ((modelMatch = modelRegex.exec(schemaContent)) !== null) {\n\t\tconst modelName = modelMatch[1];\n\t\tconst body = modelMatch[2];\n\t\tfor (const line of body.split('\\n')) {\n\t\t\tconst fieldMatch = /^\\s*([A-Za-z0-9_]+)\\s+Json.*@type\\(([^)]+)\\)/.exec(line);\n\t\t\tif (fieldMatch) {\n\t\t\t\tconst fieldName = fieldMatch[1];\n\t\t\t\tconst typeName = fieldMatch[2];\n\t\t\t\tresult[`${modelName}.${fieldName}`] = typeName;\n\t\t\t}\n\t\t}\n\t}\n\treturn result;\n}\nimport generatorHelper, { GeneratorOptions } from '@prisma/generator-helper';\nimport internals from '@prisma/internals'\nimport path from 'path'\nimport pkg from '../package.json' with { type: \"json\" }\nimport fs from 'fs'\n\n\nexport function extractCommentedTypes(schemaContent: string): Record<string, Record<string, string>> {\n\tconst commentedTypeBlocks: string[] = [];\n\tconst typeBlockRegex = /\\/\\/\\s*type\\s+([A-Za-z0-9_]+)\\s*\\{([\\s\\S]*?)\\}/g;\n\tlet match;\n\twhile ((match = typeBlockRegex.exec(schemaContent)) !== null) {\n\t\tcommentedTypeBlocks.push(match[0]);\n\t}\n\tconst typeObjects: Record<string, Record<string, string>> = {};\n\tfor (const block of commentedTypeBlocks) {\n\t\tconst headerMatch = /type\\s+([A-Za-z0-9_]+)\\s*\\{([\\s\\S]*?)\\}/.exec(block);\n\t\tif (!headerMatch) continue;\n\t\tconst typeName = headerMatch[1];\n\t\tconst body = headerMatch[2];\n\t\tconst fields: Record<string, string> = {};\n\t\tfor (const line of body.split('\\n')) {\n\t\t\tconst cleaned = line.replace(/^\\s*\\/\\//, '').trim();\n\t\t\tif (!cleaned) continue;\n\t\t\tconst fieldMatch = /^([A-Za-z0-9_]+)\\s+([A-Za-z0-9_\\[\\]?]+)$/.exec(cleaned);\n\t\t\tif (fieldMatch) {\n\t\t\t\tfields[fieldMatch[1]] = fieldMatch[2];\n\t\t\t}\n\t\t}\n\t\ttypeObjects[typeName] = fields;\n\t}\n\treturn typeObjects;\n}\n\nexport async function writeTypesFile(\n\ttypeObjects: Record<string, Record<string, string>>,\n\tclientDir: string\n) {\n\tlet typeFileContent = '// This file is auto-generated by prisma-typed-json-generator\\n\\n';\n\tfor (const [typeName, fields] of Object.entries(typeObjects)) {\n\t\ttypeFileContent += `export type ${typeName} = {\\n`;\n\t\tfor (const [field, type] of Object.entries(fields)) {\n\t\t\tlet tsType = type\n\t\t\t\t.replace(/^string$/i, 'string')\n\t\t\t\t.replace(/^int$/i, 'number')\n\t\t\t\t.replace(/^float$/i, 'number')\n\t\t\t\t.replace(/^boolean$/i, 'boolean')\n\t\t\t\t.replace(/^json$/i, 'any')\n\t\t\t\t.replace(/\\?$/, ' | null')\n\t\t\t\t.replace(/\\[\\]$/, '[]');\n\t\t\ttypeFileContent += ` ${field}: ${tsType};\\n`;\n\t\t}\n\t\ttypeFileContent += '}\\n\\n';\n\t}\n\tconst outputPath = path.join(clientDir, 'prisma-json.types.ts');\n\tawait fs.promises.mkdir(clientDir, { recursive: true });\n\tawait fs.promises.writeFile(outputPath, typeFileContent, 'utf-8');\n\treturn outputPath;\n}\n\nconst { generatorHandler } = generatorHelper;\nconst { logger } = internals;\n\ngeneratorHandler({\n\tonManifest() {\n\t\treturn {\n\t\t\tversion: pkg.version,\n\t\t\tdefaultOutput: '../generated',\n\t\t\tprettyName: \"prisma-typed-json-generator\",\n\t\t}\n\t},\n\tonGenerate: async (options: GeneratorOptions) => {\n\t\tlogger.info(`prisma-typed-json-generator:Generating...`)\n\n\t\tconst schemaFileLocation = options.generator.sourceFilePath\n\n\t\tconst clientGenerator = options.otherGenerators.find((g) => g.name === 'client')\n\t\tif (!clientGenerator) throw new Error('Prisma Client generator not found. Please ensure that generator Client is specified in your schema.');\n\n\t\tconst clientOutput = clientGenerator.output?.value\n\n\t\tconst schemaContent = await fs.promises.readFile(schemaFileLocation, 'utf-8');\n\t\tconst typeObjects = extractCommentedTypes(schemaContent);\n\n\t\tif (clientOutput) {\n\t\t\tawait writeTypesFile(typeObjects, clientOutput);\n\t\t}\n\n\t\tif (clientOutput) {\n\t\t\tconst indexDtsPath = path.join(clientOutput, 'index.d.ts');\n\t\t\tlet indexDtsContent = await fs.promises.readFile(indexDtsPath, 'utf-8');\n\t\t\tlet updated = false;\n\n\t\t\tconst jsonTypeAnnotations = extractJsonTypeAnnotations(schemaContent);\n\t\t\tfor (const [modelField, typeName] of Object.entries(jsonTypeAnnotations)) {\n\t\t\t\tconst [model, field] = modelField.split('.');\n\t\t\t\tconst payloadBlockRegex = new RegExp(`export type \\\\$${model}Payload<[^=]+=[^>]+> = {([\\\\s\\\\S]*?)}\\\\n`, 'g');\n\t\t\t\tindexDtsContent = indexDtsContent.replace(payloadBlockRegex, (block) => {\n\t\t\t\t\tconst lines = block.split('\\n');\n\t\t\t\t\tlet inScalars = false;\n\t\t\t\t\tfor (let i = 0; i < lines.length; i++) {\n\t\t\t\t\t\tif (lines[i].includes('scalars: $Extensions.GetPayloadResult<{')) inScalars = true;\n\t\t\t\t\t\tif (inScalars && lines[i].includes(`${field}: Prisma.JsonValue`)) {\n\t\t\t\t\t\t\tlines[i] = lines[i].replace('Prisma.JsonValue', `PrismaJsonTypes.${typeName}`);\n\t\t\t\t\t\t\tupdated = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (inScalars && lines[i].includes('}, ExtArgs[\"result\"]')) inScalars = false;\n\t\t\t\t\t}\n\t\t\t\t\treturn lines.join('\\n');\n\t\t\t\t});\n\t\t\t}\n\t\t\tif (updated) {\n\t\t\t\tconst importLine = `import * as PrismaJsonTypes from './prisma-json.types';`;\n\t\t\t\tif (!indexDtsContent.includes(importLine)) {\n\t\t\t\t\tindexDtsContent = indexDtsContent.replace(/(import .*?;\\n)/, `$1${importLine}\\n`);\n\t\t\t\t}\n\t\t\t\tawait fs.promises.writeFile(indexDtsPath, indexDtsContent, 'utf-8');\n\t\t\t}\n\t\t}\n\n\t\tlogger.info(`prisma-typed-json-generator:Generating...Done`)\n\t},\n})\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/utils/getEnum/index.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,EAAE,IAAI,EAAE,MAAM,EAAsB,EAAE,EAAE;IAC/D,MAAM,UAAU,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,GAAG,IAAI,KAAK,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IAE5E,OAAO,QAAQ,IAAI,QAAQ,UAAU,MAAM,CAAA;AAC5C,CAAC,CAAA","sourcesContent":["import { DMMF } from '@prisma/generator-helper'\n\nexport const genEnum = ({ name, values }: DMMF.DatamodelEnum) => {\n\tconst enumValues = values.map(({ name }) => `${name}=\"${name}\"`).join(',\\n')\n\n\treturn `enum ${name} { \\n${enumValues}\\n }`\n}\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@innovixx/prisma-typed-json-generator",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"main": "dist/index.js",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"author": "Innovixx <info@innovixx.co.uk>",
|
|
7
|
+
"license": "UNLICENSED",
|
|
8
|
+
"bin": {
|
|
9
|
+
"@innovixx/prisma-typed-json-generator": "dist/bin/index.js"
|
|
10
|
+
},
|
|
11
|
+
"scripts": {
|
|
12
|
+
"dev": "tsx src/index.ts",
|
|
13
|
+
"build": "tsc",
|
|
14
|
+
"lint": "eslint ./src/**/*.{js,jsx,ts,tsx}"
|
|
15
|
+
},
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"@prisma/client": "7.4.2",
|
|
18
|
+
"@prisma/generator-helper": "7.4.2",
|
|
19
|
+
"@prisma/internals": "^7.4.2"
|
|
20
|
+
},
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"@innovixx/eslint-config": "^3.0.11",
|
|
23
|
+
"prisma": "7.4.2",
|
|
24
|
+
"tsx": "^4.19.1",
|
|
25
|
+
"typescript": "^5.7.3"
|
|
26
|
+
}
|
|
27
|
+
}
|