prisma-flare 1.1.0 → 1.1.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.
@@ -86,7 +86,7 @@ function parseRelations(schemaContent, models) {
86
86
  if (fieldMatch) {
87
87
  const fieldName = fieldMatch[1];
88
88
  const fieldType = fieldMatch[2];
89
- const isArray = !!fieldMatch[3];
89
+ const _isArray = !!fieldMatch[3];
90
90
  if (models.includes(fieldType)) {
91
91
  const modelRelations = relations.get(modelName) || [];
92
92
  modelRelations.push({ fieldName, targetModel: fieldType });
@@ -188,7 +188,7 @@ export default class ${model} extends FlareBuilder<'${modelCamel}'> {
188
188
  registrationLines.push(`modelRegistry.register('${modelCamel}', ${model});`);
189
189
  registrationLines.push(`modelRegistry.register('${modelPlural}', ${model});`);
190
190
  });
191
- relations.forEach((rels, modelName) => {
191
+ relations.forEach((rels, _modelName) => {
192
192
  rels.forEach((rel) => {
193
193
  registrationLines.push(`modelRegistry.register('${rel.fieldName}', ${rel.targetModel});`);
194
194
  });
@@ -255,7 +255,7 @@ exports.DB = DB;
255
255
  relationMapEntries.push(` ${modelCamel}: ${model};`);
256
256
  relationMapEntries.push(` ${modelPlural}: ${model};`);
257
257
  });
258
- relations.forEach((rels, modelName) => {
258
+ relations.forEach((rels, _modelName) => {
259
259
  rels.forEach((rel) => {
260
260
  const entry = ` ${rel.fieldName}: ${rel.targetModel};`;
261
261
  if (!relationMapEntries.includes(entry)) {
@@ -63,7 +63,7 @@ function parseRelations(schemaContent, models) {
63
63
  if (fieldMatch) {
64
64
  const fieldName = fieldMatch[1];
65
65
  const fieldType = fieldMatch[2];
66
- const isArray = !!fieldMatch[3];
66
+ const _isArray = !!fieldMatch[3];
67
67
  if (models.includes(fieldType)) {
68
68
  const modelRelations = relations.get(modelName) || [];
69
69
  modelRelations.push({ fieldName, targetModel: fieldType });
@@ -165,7 +165,7 @@ export default class ${model} extends FlareBuilder<'${modelCamel}'> {
165
165
  registrationLines.push(`modelRegistry.register('${modelCamel}', ${model});`);
166
166
  registrationLines.push(`modelRegistry.register('${modelPlural}', ${model});`);
167
167
  });
168
- relations.forEach((rels, modelName) => {
168
+ relations.forEach((rels, _modelName) => {
169
169
  rels.forEach((rel) => {
170
170
  registrationLines.push(`modelRegistry.register('${rel.fieldName}', ${rel.targetModel});`);
171
171
  });
@@ -232,7 +232,7 @@ exports.DB = DB;
232
232
  relationMapEntries.push(` ${modelCamel}: ${model};`);
233
233
  relationMapEntries.push(` ${modelPlural}: ${model};`);
234
234
  });
235
- relations.forEach((rels, modelName) => {
235
+ relations.forEach((rels, _modelName) => {
236
236
  rels.forEach((rel) => {
237
237
  const entry = ` ${rel.fieldName}: ${rel.targetModel};`;
238
238
  if (!relationMapEntries.includes(entry)) {
@@ -83,7 +83,7 @@ function parseRelations(schemaContent, models) {
83
83
  if (fieldMatch) {
84
84
  const fieldName = fieldMatch[1];
85
85
  const fieldType = fieldMatch[2];
86
- const isArray = !!fieldMatch[3];
86
+ const _isArray = !!fieldMatch[3];
87
87
  if (models.includes(fieldType)) {
88
88
  const modelRelations = relations.get(modelName) || [];
89
89
  modelRelations.push({ fieldName, targetModel: fieldType });
@@ -185,7 +185,7 @@ export default class ${model} extends FlareBuilder<'${modelCamel}'> {
185
185
  registrationLines.push(`modelRegistry.register('${modelCamel}', ${model});`);
186
186
  registrationLines.push(`modelRegistry.register('${modelPlural}', ${model});`);
187
187
  });
188
- relations.forEach((rels, modelName) => {
188
+ relations.forEach((rels, _modelName) => {
189
189
  rels.forEach((rel) => {
190
190
  registrationLines.push(`modelRegistry.register('${rel.fieldName}', ${rel.targetModel});`);
191
191
  });
@@ -252,7 +252,7 @@ exports.DB = DB;
252
252
  relationMapEntries.push(` ${modelCamel}: ${model};`);
253
253
  relationMapEntries.push(` ${modelPlural}: ${model};`);
254
254
  });
255
- relations.forEach((rels, modelName) => {
255
+ relations.forEach((rels, _modelName) => {
256
256
  rels.forEach((rel) => {
257
257
  const entry = ` ${rel.fieldName}: ${rel.targetModel};`;
258
258
  if (!relationMapEntries.includes(entry)) {
@@ -283,15 +283,52 @@ ${gettersTypes}
283
283
  fs2.writeFileSync(generatedDtsPath, generatedDtsContent);
284
284
  }
285
285
 
286
+ // src/cli/generate-callbacks.ts
287
+ var fs3 = __toESM(require("fs"), 1);
288
+ var path3 = __toESM(require("path"), 1);
289
+ function generateCallbacksIndex() {
290
+ const rootDir = findProjectRoot(process.cwd());
291
+ const config = loadConfig(rootDir);
292
+ const callbacksDir = path3.join(rootDir, config.callbacksPath);
293
+ if (!fs3.existsSync(callbacksDir)) {
294
+ console.log(`\u2139\uFE0F Callbacks directory not found: ${callbacksDir}`);
295
+ return;
296
+ }
297
+ const files = fs3.readdirSync(callbacksDir);
298
+ const callbackFiles = files.filter((file) => {
299
+ if (file === "index.ts" || file === "index.js" || file.startsWith(".")) {
300
+ return false;
301
+ }
302
+ return file.endsWith(".ts") || file.endsWith(".js");
303
+ });
304
+ if (callbackFiles.length === 0) {
305
+ console.log(`\u2139\uFE0F No callback files found in: ${callbacksDir}`);
306
+ return;
307
+ }
308
+ const imports = callbackFiles.map((file) => {
309
+ const basename = file.replace(/\.(ts|js)$/, "");
310
+ return `import './${basename}';`;
311
+ }).join("\n");
312
+ const content = `// AUTO-GENERATED by prisma-flare - DO NOT EDIT
313
+ // This file imports all callbacks to ensure they are registered.
314
+ // Re-run 'npx prisma-flare generate' after adding new callback files.
315
+
316
+ ${imports}
317
+ `;
318
+ const indexPath = path3.join(callbacksDir, "index.ts");
319
+ fs3.writeFileSync(indexPath, content);
320
+ console.log(`\u2705 Generated callbacks index: ${callbacksDir}/index.ts (${callbackFiles.length} callbacks)`);
321
+ }
322
+
286
323
  // src/cli/index.ts
287
324
  var import_child_process = require("child_process");
288
- var path3 = __toESM(require("path"), 1);
289
- var fs3 = __toESM(require("fs"), 1);
325
+ var path4 = __toESM(require("path"), 1);
326
+ var fs4 = __toESM(require("fs"), 1);
290
327
  var import_url = require("url");
291
328
  var import_meta = {};
292
329
  var getDirname = () => {
293
330
  try {
294
- return path3.dirname((0, import_url.fileURLToPath)(import_meta.url));
331
+ return path4.dirname((0, import_url.fileURLToPath)(import_meta.url));
295
332
  } catch {
296
333
  return __dirname;
297
334
  }
@@ -313,6 +350,7 @@ if (!command) {
313
350
  switch (command) {
314
351
  case "generate":
315
352
  generateQueries();
353
+ generateCallbacksIndex();
316
354
  break;
317
355
  case "create":
318
356
  case "drop":
@@ -338,10 +376,10 @@ function runScript(scriptName) {
338
376
  console.error(`No script found for ${scriptName}`);
339
377
  return;
340
378
  }
341
- let scriptPath = path3.join(__dirname_, file.replace(".ts", ".js"));
342
- if (!fs3.existsSync(scriptPath)) {
343
- const cliScriptPath = path3.join(__dirname_, "cli", file.replace(".ts", ".js"));
344
- if (fs3.existsSync(cliScriptPath)) {
379
+ let scriptPath = path4.join(__dirname_, file.replace(".ts", ".js"));
380
+ if (!fs4.existsSync(scriptPath)) {
381
+ const cliScriptPath = path4.join(__dirname_, "cli", file.replace(".ts", ".js"));
382
+ if (fs4.existsSync(cliScriptPath)) {
345
383
  scriptPath = cliScriptPath;
346
384
  }
347
385
  }
package/dist/cli/index.js CHANGED
@@ -60,7 +60,7 @@ function parseRelations(schemaContent, models) {
60
60
  if (fieldMatch) {
61
61
  const fieldName = fieldMatch[1];
62
62
  const fieldType = fieldMatch[2];
63
- const isArray = !!fieldMatch[3];
63
+ const _isArray = !!fieldMatch[3];
64
64
  if (models.includes(fieldType)) {
65
65
  const modelRelations = relations.get(modelName) || [];
66
66
  modelRelations.push({ fieldName, targetModel: fieldType });
@@ -162,7 +162,7 @@ export default class ${model} extends FlareBuilder<'${modelCamel}'> {
162
162
  registrationLines.push(`modelRegistry.register('${modelCamel}', ${model});`);
163
163
  registrationLines.push(`modelRegistry.register('${modelPlural}', ${model});`);
164
164
  });
165
- relations.forEach((rels, modelName) => {
165
+ relations.forEach((rels, _modelName) => {
166
166
  rels.forEach((rel) => {
167
167
  registrationLines.push(`modelRegistry.register('${rel.fieldName}', ${rel.targetModel});`);
168
168
  });
@@ -229,7 +229,7 @@ exports.DB = DB;
229
229
  relationMapEntries.push(` ${modelCamel}: ${model};`);
230
230
  relationMapEntries.push(` ${modelPlural}: ${model};`);
231
231
  });
232
- relations.forEach((rels, modelName) => {
232
+ relations.forEach((rels, _modelName) => {
233
233
  rels.forEach((rel) => {
234
234
  const entry = ` ${rel.fieldName}: ${rel.targetModel};`;
235
235
  if (!relationMapEntries.includes(entry)) {
@@ -260,14 +260,51 @@ ${gettersTypes}
260
260
  fs2.writeFileSync(generatedDtsPath, generatedDtsContent);
261
261
  }
262
262
 
263
+ // src/cli/generate-callbacks.ts
264
+ import * as fs3 from "fs";
265
+ import * as path3 from "path";
266
+ function generateCallbacksIndex() {
267
+ const rootDir = findProjectRoot(process.cwd());
268
+ const config = loadConfig(rootDir);
269
+ const callbacksDir = path3.join(rootDir, config.callbacksPath);
270
+ if (!fs3.existsSync(callbacksDir)) {
271
+ console.log(`\u2139\uFE0F Callbacks directory not found: ${callbacksDir}`);
272
+ return;
273
+ }
274
+ const files = fs3.readdirSync(callbacksDir);
275
+ const callbackFiles = files.filter((file) => {
276
+ if (file === "index.ts" || file === "index.js" || file.startsWith(".")) {
277
+ return false;
278
+ }
279
+ return file.endsWith(".ts") || file.endsWith(".js");
280
+ });
281
+ if (callbackFiles.length === 0) {
282
+ console.log(`\u2139\uFE0F No callback files found in: ${callbacksDir}`);
283
+ return;
284
+ }
285
+ const imports = callbackFiles.map((file) => {
286
+ const basename = file.replace(/\.(ts|js)$/, "");
287
+ return `import './${basename}';`;
288
+ }).join("\n");
289
+ const content = `// AUTO-GENERATED by prisma-flare - DO NOT EDIT
290
+ // This file imports all callbacks to ensure they are registered.
291
+ // Re-run 'npx prisma-flare generate' after adding new callback files.
292
+
293
+ ${imports}
294
+ `;
295
+ const indexPath = path3.join(callbacksDir, "index.ts");
296
+ fs3.writeFileSync(indexPath, content);
297
+ console.log(`\u2705 Generated callbacks index: ${callbacksDir}/index.ts (${callbackFiles.length} callbacks)`);
298
+ }
299
+
263
300
  // src/cli/index.ts
264
301
  import { spawn } from "child_process";
265
- import * as path3 from "path";
266
- import * as fs3 from "fs";
302
+ import * as path4 from "path";
303
+ import * as fs4 from "fs";
267
304
  import { fileURLToPath } from "url";
268
305
  var getDirname = () => {
269
306
  try {
270
- return path3.dirname(fileURLToPath(import.meta.url));
307
+ return path4.dirname(fileURLToPath(import.meta.url));
271
308
  } catch {
272
309
  return __dirname;
273
310
  }
@@ -289,6 +326,7 @@ if (!command) {
289
326
  switch (command) {
290
327
  case "generate":
291
328
  generateQueries();
329
+ generateCallbacksIndex();
292
330
  break;
293
331
  case "create":
294
332
  case "drop":
@@ -314,10 +352,10 @@ function runScript(scriptName) {
314
352
  console.error(`No script found for ${scriptName}`);
315
353
  return;
316
354
  }
317
- let scriptPath = path3.join(__dirname_, file.replace(".ts", ".js"));
318
- if (!fs3.existsSync(scriptPath)) {
319
- const cliScriptPath = path3.join(__dirname_, "cli", file.replace(".ts", ".js"));
320
- if (fs3.existsSync(cliScriptPath)) {
355
+ let scriptPath = path4.join(__dirname_, file.replace(".ts", ".js"));
356
+ if (!fs4.existsSync(scriptPath)) {
357
+ const cliScriptPath = path4.join(__dirname_, "cli", file.replace(".ts", ".js"));
358
+ if (fs4.existsSync(cliScriptPath)) {
321
359
  scriptPath = cliScriptPath;
322
360
  }
323
361
  }
@@ -20,12 +20,12 @@ interface RelationModelMap {
20
20
  /**
21
21
  * Helper type to get the model class for a relation name
22
22
  */
23
- type GetRelationModel<K extends string> = K extends keyof RelationModelMap ? RelationModelMap[K] : FlareBuilder<any, {}>;
23
+ type GetRelationModel<K extends string> = K extends keyof RelationModelMap ? RelationModelMap[K] : FlareBuilder<any, Record<string, never>>;
24
24
  /**
25
25
  * FlareBuilder for chainable Prisma queries with full type safety
26
26
  * The type safety is enforced through the ModelDelegate parameter
27
27
  */
28
- declare class FlareBuilder<T extends ModelName, Args extends Record<string, any> = {}> {
28
+ declare class FlareBuilder<T extends ModelName, Args extends Record<string, any> = Record<string, never>> {
29
29
  protected model: ModelDelegate<T>;
30
30
  protected query: QueryArgs;
31
31
  constructor(model: ModelDelegate<T>, query?: QueryArgs);
@@ -122,7 +122,7 @@ declare class FlareBuilder<T extends ModelName, Args extends Record<string, any>
122
122
  * , 'OR')
123
123
  * .findMany()
124
124
  */
125
- whereGroup(callback: (builder: FlareBuilder<T, {}>) => FlareBuilder<T, any>, mode?: 'AND' | 'OR'): FlareBuilder<T, Args & {
125
+ whereGroup(callback: (builder: FlareBuilder<T, Record<string, never>>) => FlareBuilder<T, any>, mode?: 'AND' | 'OR'): FlareBuilder<T, Args & {
126
126
  where: WhereInput<T>;
127
127
  }>;
128
128
  /**
@@ -141,7 +141,7 @@ declare class FlareBuilder<T extends ModelName, Args extends Record<string, any>
141
141
  * )
142
142
  * .findMany()
143
143
  */
144
- orWhereGroup(callback: (builder: FlareBuilder<T, {}>) => FlareBuilder<T, any>): FlareBuilder<T, Args & {
144
+ orWhereGroup(callback: (builder: FlareBuilder<T, Record<string, never>>) => FlareBuilder<T, any>): FlareBuilder<T, Args & {
145
145
  where: WhereInput<T>;
146
146
  }>;
147
147
  /**
@@ -20,12 +20,12 @@ interface RelationModelMap {
20
20
  /**
21
21
  * Helper type to get the model class for a relation name
22
22
  */
23
- type GetRelationModel<K extends string> = K extends keyof RelationModelMap ? RelationModelMap[K] : FlareBuilder<any, {}>;
23
+ type GetRelationModel<K extends string> = K extends keyof RelationModelMap ? RelationModelMap[K] : FlareBuilder<any, Record<string, never>>;
24
24
  /**
25
25
  * FlareBuilder for chainable Prisma queries with full type safety
26
26
  * The type safety is enforced through the ModelDelegate parameter
27
27
  */
28
- declare class FlareBuilder<T extends ModelName, Args extends Record<string, any> = {}> {
28
+ declare class FlareBuilder<T extends ModelName, Args extends Record<string, any> = Record<string, never>> {
29
29
  protected model: ModelDelegate<T>;
30
30
  protected query: QueryArgs;
31
31
  constructor(model: ModelDelegate<T>, query?: QueryArgs);
@@ -122,7 +122,7 @@ declare class FlareBuilder<T extends ModelName, Args extends Record<string, any>
122
122
  * , 'OR')
123
123
  * .findMany()
124
124
  */
125
- whereGroup(callback: (builder: FlareBuilder<T, {}>) => FlareBuilder<T, any>, mode?: 'AND' | 'OR'): FlareBuilder<T, Args & {
125
+ whereGroup(callback: (builder: FlareBuilder<T, Record<string, never>>) => FlareBuilder<T, any>, mode?: 'AND' | 'OR'): FlareBuilder<T, Args & {
126
126
  where: WhereInput<T>;
127
127
  }>;
128
128
  /**
@@ -141,7 +141,7 @@ declare class FlareBuilder<T extends ModelName, Args extends Record<string, any>
141
141
  * )
142
142
  * .findMany()
143
143
  */
144
- orWhereGroup(callback: (builder: FlareBuilder<T, {}>) => FlareBuilder<T, any>): FlareBuilder<T, Args & {
144
+ orWhereGroup(callback: (builder: FlareBuilder<T, Record<string, never>>) => FlareBuilder<T, any>): FlareBuilder<T, Args & {
145
145
  where: WhereInput<T>;
146
146
  }>;
147
147
  /**
package/dist/index.cjs CHANGED
@@ -52,7 +52,7 @@ __export(index_exports, {
52
52
  module.exports = __toCommonJS(index_exports);
53
53
 
54
54
  // src/core/extendedPrismaClient.ts
55
- var import_client = require("@prisma/client");
55
+ var import_client2 = require("@prisma/client");
56
56
 
57
57
  // src/core/modelRegistry.ts
58
58
  var ModelRegistry = class {
@@ -710,53 +710,6 @@ var FlareBuilder = class _FlareBuilder {
710
710
  }
711
711
  };
712
712
 
713
- // src/core/extendedPrismaClient.ts
714
- var FlareClient = class extends import_client.PrismaClient {
715
- constructor(options = {}) {
716
- super(options);
717
- }
718
- /**
719
- * Creates a new FlareBuilder instance for the specified model.
720
- * @param modelName - The name of the model.
721
- * @returns FlareBuilder instance
722
- */
723
- from(modelName) {
724
- const key = modelName.charAt(0).toLowerCase() + modelName.slice(1);
725
- const model = this[key];
726
- if (!model) {
727
- throw new Error(`Model ${modelName} does not exist on PrismaClient.`);
728
- }
729
- return new FlareBuilder(model);
730
- }
731
- /**
732
- * Executes a transaction with the FlareClient capabilities.
733
- * @param fn - The transaction function.
734
- * @param options - Transaction options.
735
- * @returns The result of the transaction.
736
- */
737
- async transaction(fn, options) {
738
- return super.$transaction(async (tx) => {
739
- const extendedTx = new Proxy(tx, {
740
- get: (target, prop, receiver) => {
741
- if (prop === "from") {
742
- return (modelName) => {
743
- const key = modelName.charAt(0).toLowerCase() + modelName.slice(1);
744
- const model = target[key];
745
- if (!model) {
746
- throw new Error(`Model ${modelName} does not exist on TransactionClient.`);
747
- }
748
- return new FlareBuilder(model);
749
- };
750
- }
751
- return Reflect.get(target, prop, receiver);
752
- }
753
- });
754
- return fn(extendedTx);
755
- }, options);
756
- }
757
- };
758
- var ExtendedPrismaClient = FlareClient;
759
-
760
713
  // src/core/hookRegistry.ts
761
714
  function valuesEqual(a, b) {
762
715
  if (a == null && b == null) return true;
@@ -928,74 +881,8 @@ var HookRegistry = class {
928
881
  var hookRegistry = new HookRegistry();
929
882
  var hookRegistry_default = hookRegistry;
930
883
 
931
- // src/core/hooks.ts
932
- function normalizeModelName(model) {
933
- return model.toLowerCase();
934
- }
935
- function beforeCreate(model, callback) {
936
- hookRegistry_default.addHook(normalizeModelName(model), "create", "before", callback);
937
- }
938
- function beforeDelete(model, callback) {
939
- hookRegistry_default.addHook(normalizeModelName(model), "delete", "before", callback);
940
- }
941
- function afterCreate(model, callback) {
942
- hookRegistry_default.addHook(normalizeModelName(model), "create", "after", callback);
943
- }
944
- function afterDelete(model, callback) {
945
- hookRegistry_default.addHook(normalizeModelName(model), "delete", "after", callback);
946
- }
947
- function beforeUpdate(model, callback) {
948
- hookRegistry_default.addHook(normalizeModelName(model), "update", "before", callback);
949
- }
950
- function afterUpdate(model, callback) {
951
- hookRegistry_default.addHook(normalizeModelName(model), "update", "after", callback);
952
- }
953
- function afterChange(model, column, callback) {
954
- hookRegistry_default.addColumnHook(normalizeModelName(model), column, callback);
955
- }
956
- function afterUpsert(model, callback) {
957
- hookRegistry_default.addHook(normalizeModelName(model), "upsert", "after", callback);
958
- }
959
-
960
- // src/core/hookMiddleware.ts
961
- var import_client2 = require("@prisma/client");
962
-
963
- // src/cli/config.ts
964
- var fs = __toESM(require("fs"), 1);
965
- var path = __toESM(require("path"), 1);
966
- function findProjectRoot(currentDir) {
967
- if (fs.existsSync(path.join(currentDir, "package.json"))) {
968
- return currentDir;
969
- }
970
- const parentDir = path.dirname(currentDir);
971
- if (parentDir === currentDir) {
972
- throw new Error("Could not find package.json");
973
- }
974
- return findProjectRoot(parentDir);
975
- }
976
- function loadConfig(rootDir) {
977
- const projectRoot = rootDir || findProjectRoot(process.cwd());
978
- const configPath = path.join(projectRoot, "prisma-flare.config.json");
979
- let config = {
980
- modelsPath: "prisma/models",
981
- dbPath: "prisma/db",
982
- callbacksPath: "prisma/callbacks"
983
- };
984
- if (fs.existsSync(configPath)) {
985
- try {
986
- const configFile = fs.readFileSync(configPath, "utf-8");
987
- const userConfig = JSON.parse(configFile);
988
- config = { ...config, ...userConfig };
989
- } catch {
990
- console.warn("\u26A0\uFE0F Could not read prisma-flare.config.json, using defaults.");
991
- }
992
- }
993
- return {
994
- ...config
995
- };
996
- }
997
-
998
884
  // src/core/hookMiddleware.ts
885
+ var import_client = require("@prisma/client");
999
886
  var import_fs = __toESM(require("fs"), 1);
1000
887
  var import_path = __toESM(require("path"), 1);
1001
888
  function supportsTypeScriptImports() {
@@ -1094,7 +981,7 @@ function supportsPrisma6Middleware(prisma) {
1094
981
  return typeof prisma.$use === "function";
1095
982
  }
1096
983
  function createHooksExtension(basePrisma) {
1097
- return import_client2.Prisma.defineExtension({
984
+ return import_client.Prisma.defineExtension({
1098
985
  name: "prisma-flare-hooks",
1099
986
  query: {
1100
987
  $allModels: {
@@ -1117,23 +1004,102 @@ function registerHooksLegacy(prisma) {
1117
1004
  return executeHookLogic(prisma, model, action, args, () => next(params));
1118
1005
  });
1119
1006
  }
1120
- async function registerHooks(prisma) {
1121
- let client;
1007
+ function registerHooks(prisma) {
1122
1008
  if (supportsPrisma6Middleware(prisma)) {
1123
1009
  registerHooksLegacy(prisma);
1124
- client = prisma;
1010
+ return prisma;
1125
1011
  } else {
1126
1012
  const extension = createHooksExtension(prisma);
1127
- client = prisma.$extends(extension);
1013
+ return prisma.$extends(extension);
1014
+ }
1015
+ }
1016
+
1017
+ // src/core/extendedPrismaClient.ts
1018
+ function supportsPrisma6Middleware2(prisma) {
1019
+ return typeof prisma.$use === "function";
1020
+ }
1021
+ var FlareClient = class extends import_client2.PrismaClient {
1022
+ constructor(options = {}) {
1023
+ const { callbacks = true, ...prismaOptions } = options;
1024
+ super(prismaOptions);
1025
+ if (callbacks) {
1026
+ if (supportsPrisma6Middleware2(this)) {
1027
+ registerHooksLegacy(this);
1028
+ } else {
1029
+ const extension = createHooksExtension(this);
1030
+ return this.$extends(extension);
1031
+ }
1032
+ }
1033
+ }
1034
+ /**
1035
+ * Creates a new FlareBuilder instance for the specified model.
1036
+ * @param modelName - The name of the model.
1037
+ * @returns FlareBuilder instance
1038
+ */
1039
+ from(modelName) {
1040
+ const key = modelName.charAt(0).toLowerCase() + modelName.slice(1);
1041
+ const model = this[key];
1042
+ if (!model) {
1043
+ throw new Error(`Model ${modelName} does not exist on PrismaClient.`);
1044
+ }
1045
+ return new FlareBuilder(model);
1128
1046
  }
1129
- try {
1130
- const config = loadConfig();
1131
- const projectRoot = findProjectRoot(process.cwd());
1132
- const callbacksPath = import_path.default.join(projectRoot, config.callbacksPath);
1133
- await loadCallbacks(callbacksPath);
1134
- } catch {
1047
+ /**
1048
+ * Executes a transaction with the FlareClient capabilities.
1049
+ * @param fn - The transaction function.
1050
+ * @param options - Transaction options.
1051
+ * @returns The result of the transaction.
1052
+ */
1053
+ async transaction(fn, options) {
1054
+ return super.$transaction(async (tx) => {
1055
+ const extendedTx = new Proxy(tx, {
1056
+ get: (target, prop, receiver) => {
1057
+ if (prop === "from") {
1058
+ return (modelName) => {
1059
+ const key = modelName.charAt(0).toLowerCase() + modelName.slice(1);
1060
+ const model = target[key];
1061
+ if (!model) {
1062
+ throw new Error(`Model ${modelName} does not exist on TransactionClient.`);
1063
+ }
1064
+ return new FlareBuilder(model);
1065
+ };
1066
+ }
1067
+ return Reflect.get(target, prop, receiver);
1068
+ }
1069
+ });
1070
+ return fn(extendedTx);
1071
+ }, options);
1135
1072
  }
1136
- return client;
1073
+ };
1074
+ var ExtendedPrismaClient = FlareClient;
1075
+
1076
+ // src/core/hooks.ts
1077
+ function normalizeModelName(model) {
1078
+ return model.toLowerCase();
1079
+ }
1080
+ function beforeCreate(model, callback) {
1081
+ hookRegistry_default.addHook(normalizeModelName(model), "create", "before", callback);
1082
+ }
1083
+ function beforeDelete(model, callback) {
1084
+ hookRegistry_default.addHook(normalizeModelName(model), "delete", "before", callback);
1085
+ }
1086
+ function afterCreate(model, callback) {
1087
+ hookRegistry_default.addHook(normalizeModelName(model), "create", "after", callback);
1088
+ }
1089
+ function afterDelete(model, callback) {
1090
+ hookRegistry_default.addHook(normalizeModelName(model), "delete", "after", callback);
1091
+ }
1092
+ function beforeUpdate(model, callback) {
1093
+ hookRegistry_default.addHook(normalizeModelName(model), "update", "before", callback);
1094
+ }
1095
+ function afterUpdate(model, callback) {
1096
+ hookRegistry_default.addHook(normalizeModelName(model), "update", "after", callback);
1097
+ }
1098
+ function afterChange(model, column, callback) {
1099
+ hookRegistry_default.addColumnHook(normalizeModelName(model), column, callback);
1100
+ }
1101
+ function afterUpsert(model, callback) {
1102
+ hookRegistry_default.addHook(normalizeModelName(model), "upsert", "after", callback);
1137
1103
  }
1138
1104
 
1139
1105
  // src/core/adapters/postgres.ts
@@ -1216,8 +1182,8 @@ function parseDatabaseUrl(url) {
1216
1182
  }
1217
1183
 
1218
1184
  // src/core/adapters/sqlite.ts
1219
- var fs3 = __toESM(require("fs"), 1);
1220
- var path3 = __toESM(require("path"), 1);
1185
+ var fs2 = __toESM(require("fs"), 1);
1186
+ var path2 = __toESM(require("path"), 1);
1221
1187
  var SqliteAdapter = {
1222
1188
  name: "sqlite",
1223
1189
  matches(url) {
@@ -1225,13 +1191,13 @@ var SqliteAdapter = {
1225
1191
  },
1226
1192
  async create(url) {
1227
1193
  const filePath = parseSqliteUrl(url);
1228
- const dir = path3.dirname(filePath);
1194
+ const dir = path2.dirname(filePath);
1229
1195
  try {
1230
- if (!fs3.existsSync(dir)) {
1231
- fs3.mkdirSync(dir, { recursive: true });
1196
+ if (!fs2.existsSync(dir)) {
1197
+ fs2.mkdirSync(dir, { recursive: true });
1232
1198
  }
1233
- if (!fs3.existsSync(filePath)) {
1234
- fs3.writeFileSync(filePath, "");
1199
+ if (!fs2.existsSync(filePath)) {
1200
+ fs2.writeFileSync(filePath, "");
1235
1201
  console.log(`\u2705 SQLite database created at "${filePath}"`);
1236
1202
  } else {
1237
1203
  console.log(`\u26A0\uFE0F SQLite database already exists at "${filePath}"`);
@@ -1244,20 +1210,20 @@ var SqliteAdapter = {
1244
1210
  async drop(url) {
1245
1211
  const filePath = parseSqliteUrl(url);
1246
1212
  try {
1247
- if (fs3.existsSync(filePath)) {
1248
- fs3.unlinkSync(filePath);
1213
+ if (fs2.existsSync(filePath)) {
1214
+ fs2.unlinkSync(filePath);
1249
1215
  console.log(`\u2705 SQLite database at "${filePath}" dropped successfully.`);
1250
1216
  } else {
1251
1217
  console.log(`\u26A0\uFE0F SQLite database does not exist at "${filePath}"`);
1252
1218
  }
1253
- if (fs3.existsSync(`${filePath}-journal`)) {
1254
- fs3.unlinkSync(`${filePath}-journal`);
1219
+ if (fs2.existsSync(`${filePath}-journal`)) {
1220
+ fs2.unlinkSync(`${filePath}-journal`);
1255
1221
  }
1256
- if (fs3.existsSync(`${filePath}-wal`)) {
1257
- fs3.unlinkSync(`${filePath}-wal`);
1222
+ if (fs2.existsSync(`${filePath}-wal`)) {
1223
+ fs2.unlinkSync(`${filePath}-wal`);
1258
1224
  }
1259
- if (fs3.existsSync(`${filePath}-shm`)) {
1260
- fs3.unlinkSync(`${filePath}-shm`);
1225
+ if (fs2.existsSync(`${filePath}-shm`)) {
1226
+ fs2.unlinkSync(`${filePath}-shm`);
1261
1227
  }
1262
1228
  } catch (error) {
1263
1229
  console.error("\u274C Error dropping SQLite database:", error);
@@ -1267,8 +1233,8 @@ var SqliteAdapter = {
1267
1233
  };
1268
1234
  function parseSqliteUrl(url) {
1269
1235
  let cleanPath = url.replace(/^file:/, "");
1270
- if (!path3.isAbsolute(cleanPath)) {
1271
- cleanPath = path3.resolve(process.cwd(), cleanPath);
1236
+ if (!path2.isAbsolute(cleanPath)) {
1237
+ cleanPath = path2.resolve(process.cwd(), cleanPath);
1272
1238
  }
1273
1239
  return cleanPath;
1274
1240
  }
package/dist/index.d.cts CHANGED
@@ -8,8 +8,18 @@ import { M as ModelName, l as PrismaOperation, m as HookTiming, B as BeforeHookC
8
8
  export { r as AggregateResult, o as CreateArgs, C as CreateData, p as CreateManyArgs, b as CreateManyData, c as DeleteArgs, n as FindFirstArgs, F as FindManyArgs, a as ModelDelegate, R as RecordType, q as UpdateArgs, f as UpsertArgs } from './prisma.types-nGNe1CG8.cjs';
9
9
  export { afterChange, afterCreate, afterDelete, afterUpdate, afterUpsert, beforeCreate, beforeDelete, beforeUpdate } from './core/hooks.cjs';
10
10
 
11
+ interface FlareClientOptions extends PrismaClientOptions {
12
+ /**
13
+ * Enable callbacks/hooks middleware. When true (default), the middleware
14
+ * that executes your registered callbacks (beforeCreate, afterUpdate, etc.)
15
+ * is automatically attached.
16
+ *
17
+ * @default true
18
+ */
19
+ callbacks?: boolean;
20
+ }
11
21
  declare class FlareClient extends PrismaClient {
12
- constructor(options?: PrismaClientOptions);
22
+ constructor(options?: FlareClientOptions);
13
23
  /**
14
24
  * Creates a new FlareBuilder instance for the specified model.
15
25
  * @param modelName - The name of the model.
@@ -186,22 +196,21 @@ declare function createHooksExtension(basePrisma: PrismaClient): (client: any) =
186
196
  */
187
197
  declare function registerHooksLegacy(prisma: PrismaClient): void;
188
198
  /**
189
- * Registers hooks on the Prisma client and automatically loads callbacks.
190
- * Automatically detects Prisma version and uses the appropriate API:
191
- * - Prisma ≤6: Uses $use middleware
192
- * - Prisma 7+: Returns extended client with hooks extension
193
- *
194
- * Callbacks are loaded from the path specified in prisma-flare.config.json
195
- * (defaults to 'prisma/callbacks'). Set `callbacksPath` in config to customize.
196
- *
197
- * @param prisma - The Prisma client instance
198
- * @returns Promise resolving to the Prisma client (possibly extended for Prisma 7+)
199
+ * @deprecated Use `new FlareClient()` instead. FlareClient now automatically
200
+ * attaches the callbacks middleware. This function will be removed in a future version.
199
201
  *
200
202
  * @example
201
- * // In your db setup file:
202
- * export const db = await registerHooks(new FlareClient());
203
+ * // Old way (deprecated):
204
+ * import './callbacks';
205
+ * import { FlareClient, registerHooks } from 'prisma-flare';
206
+ * export const db = registerHooks(new FlareClient());
207
+ *
208
+ * // New way:
209
+ * import './callbacks';
210
+ * import { FlareClient } from 'prisma-flare';
211
+ * export const db = new FlareClient();
203
212
  */
204
- declare function registerHooks<T extends PrismaClient>(prisma: T): Promise<T>;
213
+ declare function registerHooks<T extends PrismaClient>(prisma: T): T;
205
214
 
206
215
  /**
207
216
  * Database Adapter Interface
@@ -234,4 +243,4 @@ declare class AdapterRegistry {
234
243
  }
235
244
  declare const registry: AdapterRegistry;
236
245
 
237
- export { AfterHookCallback, BeforeHookCallback, ColumnChangeCallback, type DatabaseAdapter, ExtendedPrismaClient, FlareBuilder, FlareClient, type HookConfig, HookTiming, ModelName, PrismaOperation, createHooksExtension, registry as dbAdapterRegistry, hookRegistry, loadCallbacks, modelRegistry, registerHooks, registerHooksLegacy };
246
+ export { AfterHookCallback, BeforeHookCallback, ColumnChangeCallback, type DatabaseAdapter, ExtendedPrismaClient, FlareBuilder, FlareClient, type FlareClientOptions, type HookConfig, HookTiming, ModelName, PrismaOperation, createHooksExtension, registry as dbAdapterRegistry, hookRegistry, loadCallbacks, modelRegistry, registerHooks, registerHooksLegacy };
package/dist/index.d.ts CHANGED
@@ -8,8 +8,18 @@ import { M as ModelName, l as PrismaOperation, m as HookTiming, B as BeforeHookC
8
8
  export { r as AggregateResult, o as CreateArgs, C as CreateData, p as CreateManyArgs, b as CreateManyData, c as DeleteArgs, n as FindFirstArgs, F as FindManyArgs, a as ModelDelegate, R as RecordType, q as UpdateArgs, f as UpsertArgs } from './prisma.types-nGNe1CG8.js';
9
9
  export { afterChange, afterCreate, afterDelete, afterUpdate, afterUpsert, beforeCreate, beforeDelete, beforeUpdate } from './core/hooks.js';
10
10
 
11
+ interface FlareClientOptions extends PrismaClientOptions {
12
+ /**
13
+ * Enable callbacks/hooks middleware. When true (default), the middleware
14
+ * that executes your registered callbacks (beforeCreate, afterUpdate, etc.)
15
+ * is automatically attached.
16
+ *
17
+ * @default true
18
+ */
19
+ callbacks?: boolean;
20
+ }
11
21
  declare class FlareClient extends PrismaClient {
12
- constructor(options?: PrismaClientOptions);
22
+ constructor(options?: FlareClientOptions);
13
23
  /**
14
24
  * Creates a new FlareBuilder instance for the specified model.
15
25
  * @param modelName - The name of the model.
@@ -186,22 +196,21 @@ declare function createHooksExtension(basePrisma: PrismaClient): (client: any) =
186
196
  */
187
197
  declare function registerHooksLegacy(prisma: PrismaClient): void;
188
198
  /**
189
- * Registers hooks on the Prisma client and automatically loads callbacks.
190
- * Automatically detects Prisma version and uses the appropriate API:
191
- * - Prisma ≤6: Uses $use middleware
192
- * - Prisma 7+: Returns extended client with hooks extension
193
- *
194
- * Callbacks are loaded from the path specified in prisma-flare.config.json
195
- * (defaults to 'prisma/callbacks'). Set `callbacksPath` in config to customize.
196
- *
197
- * @param prisma - The Prisma client instance
198
- * @returns Promise resolving to the Prisma client (possibly extended for Prisma 7+)
199
+ * @deprecated Use `new FlareClient()` instead. FlareClient now automatically
200
+ * attaches the callbacks middleware. This function will be removed in a future version.
199
201
  *
200
202
  * @example
201
- * // In your db setup file:
202
- * export const db = await registerHooks(new FlareClient());
203
+ * // Old way (deprecated):
204
+ * import './callbacks';
205
+ * import { FlareClient, registerHooks } from 'prisma-flare';
206
+ * export const db = registerHooks(new FlareClient());
207
+ *
208
+ * // New way:
209
+ * import './callbacks';
210
+ * import { FlareClient } from 'prisma-flare';
211
+ * export const db = new FlareClient();
203
212
  */
204
- declare function registerHooks<T extends PrismaClient>(prisma: T): Promise<T>;
213
+ declare function registerHooks<T extends PrismaClient>(prisma: T): T;
205
214
 
206
215
  /**
207
216
  * Database Adapter Interface
@@ -234,4 +243,4 @@ declare class AdapterRegistry {
234
243
  }
235
244
  declare const registry: AdapterRegistry;
236
245
 
237
- export { AfterHookCallback, BeforeHookCallback, ColumnChangeCallback, type DatabaseAdapter, ExtendedPrismaClient, FlareBuilder, FlareClient, type HookConfig, HookTiming, ModelName, PrismaOperation, createHooksExtension, registry as dbAdapterRegistry, hookRegistry, loadCallbacks, modelRegistry, registerHooks, registerHooksLegacy };
246
+ export { AfterHookCallback, BeforeHookCallback, ColumnChangeCallback, type DatabaseAdapter, ExtendedPrismaClient, FlareBuilder, FlareClient, type FlareClientOptions, type HookConfig, HookTiming, ModelName, PrismaOperation, createHooksExtension, registry as dbAdapterRegistry, hookRegistry, loadCallbacks, modelRegistry, registerHooks, registerHooksLegacy };
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/core/extendedPrismaClient.ts
2
- import { PrismaClient } from "@prisma/client";
2
+ import { PrismaClient as PrismaClient2 } from "@prisma/client";
3
3
 
4
4
  // src/core/modelRegistry.ts
5
5
  var ModelRegistry = class {
@@ -657,53 +657,6 @@ var FlareBuilder = class _FlareBuilder {
657
657
  }
658
658
  };
659
659
 
660
- // src/core/extendedPrismaClient.ts
661
- var FlareClient = class extends PrismaClient {
662
- constructor(options = {}) {
663
- super(options);
664
- }
665
- /**
666
- * Creates a new FlareBuilder instance for the specified model.
667
- * @param modelName - The name of the model.
668
- * @returns FlareBuilder instance
669
- */
670
- from(modelName) {
671
- const key = modelName.charAt(0).toLowerCase() + modelName.slice(1);
672
- const model = this[key];
673
- if (!model) {
674
- throw new Error(`Model ${modelName} does not exist on PrismaClient.`);
675
- }
676
- return new FlareBuilder(model);
677
- }
678
- /**
679
- * Executes a transaction with the FlareClient capabilities.
680
- * @param fn - The transaction function.
681
- * @param options - Transaction options.
682
- * @returns The result of the transaction.
683
- */
684
- async transaction(fn, options) {
685
- return super.$transaction(async (tx) => {
686
- const extendedTx = new Proxy(tx, {
687
- get: (target, prop, receiver) => {
688
- if (prop === "from") {
689
- return (modelName) => {
690
- const key = modelName.charAt(0).toLowerCase() + modelName.slice(1);
691
- const model = target[key];
692
- if (!model) {
693
- throw new Error(`Model ${modelName} does not exist on TransactionClient.`);
694
- }
695
- return new FlareBuilder(model);
696
- };
697
- }
698
- return Reflect.get(target, prop, receiver);
699
- }
700
- });
701
- return fn(extendedTx);
702
- }, options);
703
- }
704
- };
705
- var ExtendedPrismaClient = FlareClient;
706
-
707
660
  // src/core/hookRegistry.ts
708
661
  function valuesEqual(a, b) {
709
662
  if (a == null && b == null) return true;
@@ -875,76 +828,10 @@ var HookRegistry = class {
875
828
  var hookRegistry = new HookRegistry();
876
829
  var hookRegistry_default = hookRegistry;
877
830
 
878
- // src/core/hooks.ts
879
- function normalizeModelName(model) {
880
- return model.toLowerCase();
881
- }
882
- function beforeCreate(model, callback) {
883
- hookRegistry_default.addHook(normalizeModelName(model), "create", "before", callback);
884
- }
885
- function beforeDelete(model, callback) {
886
- hookRegistry_default.addHook(normalizeModelName(model), "delete", "before", callback);
887
- }
888
- function afterCreate(model, callback) {
889
- hookRegistry_default.addHook(normalizeModelName(model), "create", "after", callback);
890
- }
891
- function afterDelete(model, callback) {
892
- hookRegistry_default.addHook(normalizeModelName(model), "delete", "after", callback);
893
- }
894
- function beforeUpdate(model, callback) {
895
- hookRegistry_default.addHook(normalizeModelName(model), "update", "before", callback);
896
- }
897
- function afterUpdate(model, callback) {
898
- hookRegistry_default.addHook(normalizeModelName(model), "update", "after", callback);
899
- }
900
- function afterChange(model, column, callback) {
901
- hookRegistry_default.addColumnHook(normalizeModelName(model), column, callback);
902
- }
903
- function afterUpsert(model, callback) {
904
- hookRegistry_default.addHook(normalizeModelName(model), "upsert", "after", callback);
905
- }
906
-
907
831
  // src/core/hookMiddleware.ts
908
832
  import { Prisma } from "@prisma/client";
909
-
910
- // src/cli/config.ts
911
- import * as fs from "fs";
912
- import * as path from "path";
913
- function findProjectRoot(currentDir) {
914
- if (fs.existsSync(path.join(currentDir, "package.json"))) {
915
- return currentDir;
916
- }
917
- const parentDir = path.dirname(currentDir);
918
- if (parentDir === currentDir) {
919
- throw new Error("Could not find package.json");
920
- }
921
- return findProjectRoot(parentDir);
922
- }
923
- function loadConfig(rootDir) {
924
- const projectRoot = rootDir || findProjectRoot(process.cwd());
925
- const configPath = path.join(projectRoot, "prisma-flare.config.json");
926
- let config = {
927
- modelsPath: "prisma/models",
928
- dbPath: "prisma/db",
929
- callbacksPath: "prisma/callbacks"
930
- };
931
- if (fs.existsSync(configPath)) {
932
- try {
933
- const configFile = fs.readFileSync(configPath, "utf-8");
934
- const userConfig = JSON.parse(configFile);
935
- config = { ...config, ...userConfig };
936
- } catch {
937
- console.warn("\u26A0\uFE0F Could not read prisma-flare.config.json, using defaults.");
938
- }
939
- }
940
- return {
941
- ...config
942
- };
943
- }
944
-
945
- // src/core/hookMiddleware.ts
946
- import fs2 from "fs";
947
- import path2 from "path";
833
+ import fs from "fs";
834
+ import path from "path";
948
835
  function supportsTypeScriptImports() {
949
836
  if (process.env.TS_NODE || /* @__PURE__ */ Symbol.for("ts-node.register.instance") in process) {
950
837
  return true;
@@ -962,16 +849,16 @@ function supportsTypeScriptImports() {
962
849
  }
963
850
  async function loadCallbacks(callbacksDir) {
964
851
  if (!callbacksDir) {
965
- callbacksDir = path2.join(process.cwd(), "prisma", "callbacks");
852
+ callbacksDir = path.join(process.cwd(), "prisma", "callbacks");
966
853
  }
967
- if (!fs2.existsSync(callbacksDir)) {
854
+ if (!fs.existsSync(callbacksDir)) {
968
855
  console.warn(`Callbacks directory not found: ${callbacksDir}`);
969
856
  return;
970
857
  }
971
858
  const canImportTs = supportsTypeScriptImports();
972
- const files = fs2.readdirSync(callbacksDir);
859
+ const files = fs.readdirSync(callbacksDir);
973
860
  for (const file of files) {
974
- const filePath = path2.join(callbacksDir, file);
861
+ const filePath = path.join(callbacksDir, file);
975
862
  if (file.endsWith(".js")) {
976
863
  await import(filePath);
977
864
  } else if (file.endsWith(".ts") && canImportTs) {
@@ -1064,23 +951,102 @@ function registerHooksLegacy(prisma) {
1064
951
  return executeHookLogic(prisma, model, action, args, () => next(params));
1065
952
  });
1066
953
  }
1067
- async function registerHooks(prisma) {
1068
- let client;
954
+ function registerHooks(prisma) {
1069
955
  if (supportsPrisma6Middleware(prisma)) {
1070
956
  registerHooksLegacy(prisma);
1071
- client = prisma;
957
+ return prisma;
1072
958
  } else {
1073
959
  const extension = createHooksExtension(prisma);
1074
- client = prisma.$extends(extension);
960
+ return prisma.$extends(extension);
1075
961
  }
1076
- try {
1077
- const config = loadConfig();
1078
- const projectRoot = findProjectRoot(process.cwd());
1079
- const callbacksPath = path2.join(projectRoot, config.callbacksPath);
1080
- await loadCallbacks(callbacksPath);
1081
- } catch {
962
+ }
963
+
964
+ // src/core/extendedPrismaClient.ts
965
+ function supportsPrisma6Middleware2(prisma) {
966
+ return typeof prisma.$use === "function";
967
+ }
968
+ var FlareClient = class extends PrismaClient2 {
969
+ constructor(options = {}) {
970
+ const { callbacks = true, ...prismaOptions } = options;
971
+ super(prismaOptions);
972
+ if (callbacks) {
973
+ if (supportsPrisma6Middleware2(this)) {
974
+ registerHooksLegacy(this);
975
+ } else {
976
+ const extension = createHooksExtension(this);
977
+ return this.$extends(extension);
978
+ }
979
+ }
980
+ }
981
+ /**
982
+ * Creates a new FlareBuilder instance for the specified model.
983
+ * @param modelName - The name of the model.
984
+ * @returns FlareBuilder instance
985
+ */
986
+ from(modelName) {
987
+ const key = modelName.charAt(0).toLowerCase() + modelName.slice(1);
988
+ const model = this[key];
989
+ if (!model) {
990
+ throw new Error(`Model ${modelName} does not exist on PrismaClient.`);
991
+ }
992
+ return new FlareBuilder(model);
993
+ }
994
+ /**
995
+ * Executes a transaction with the FlareClient capabilities.
996
+ * @param fn - The transaction function.
997
+ * @param options - Transaction options.
998
+ * @returns The result of the transaction.
999
+ */
1000
+ async transaction(fn, options) {
1001
+ return super.$transaction(async (tx) => {
1002
+ const extendedTx = new Proxy(tx, {
1003
+ get: (target, prop, receiver) => {
1004
+ if (prop === "from") {
1005
+ return (modelName) => {
1006
+ const key = modelName.charAt(0).toLowerCase() + modelName.slice(1);
1007
+ const model = target[key];
1008
+ if (!model) {
1009
+ throw new Error(`Model ${modelName} does not exist on TransactionClient.`);
1010
+ }
1011
+ return new FlareBuilder(model);
1012
+ };
1013
+ }
1014
+ return Reflect.get(target, prop, receiver);
1015
+ }
1016
+ });
1017
+ return fn(extendedTx);
1018
+ }, options);
1082
1019
  }
1083
- return client;
1020
+ };
1021
+ var ExtendedPrismaClient = FlareClient;
1022
+
1023
+ // src/core/hooks.ts
1024
+ function normalizeModelName(model) {
1025
+ return model.toLowerCase();
1026
+ }
1027
+ function beforeCreate(model, callback) {
1028
+ hookRegistry_default.addHook(normalizeModelName(model), "create", "before", callback);
1029
+ }
1030
+ function beforeDelete(model, callback) {
1031
+ hookRegistry_default.addHook(normalizeModelName(model), "delete", "before", callback);
1032
+ }
1033
+ function afterCreate(model, callback) {
1034
+ hookRegistry_default.addHook(normalizeModelName(model), "create", "after", callback);
1035
+ }
1036
+ function afterDelete(model, callback) {
1037
+ hookRegistry_default.addHook(normalizeModelName(model), "delete", "after", callback);
1038
+ }
1039
+ function beforeUpdate(model, callback) {
1040
+ hookRegistry_default.addHook(normalizeModelName(model), "update", "before", callback);
1041
+ }
1042
+ function afterUpdate(model, callback) {
1043
+ hookRegistry_default.addHook(normalizeModelName(model), "update", "after", callback);
1044
+ }
1045
+ function afterChange(model, column, callback) {
1046
+ hookRegistry_default.addColumnHook(normalizeModelName(model), column, callback);
1047
+ }
1048
+ function afterUpsert(model, callback) {
1049
+ hookRegistry_default.addHook(normalizeModelName(model), "upsert", "after", callback);
1084
1050
  }
1085
1051
 
1086
1052
  // src/core/adapters/postgres.ts
@@ -1163,8 +1129,8 @@ function parseDatabaseUrl(url) {
1163
1129
  }
1164
1130
 
1165
1131
  // src/core/adapters/sqlite.ts
1166
- import * as fs3 from "fs";
1167
- import * as path3 from "path";
1132
+ import * as fs2 from "fs";
1133
+ import * as path2 from "path";
1168
1134
  var SqliteAdapter = {
1169
1135
  name: "sqlite",
1170
1136
  matches(url) {
@@ -1172,13 +1138,13 @@ var SqliteAdapter = {
1172
1138
  },
1173
1139
  async create(url) {
1174
1140
  const filePath = parseSqliteUrl(url);
1175
- const dir = path3.dirname(filePath);
1141
+ const dir = path2.dirname(filePath);
1176
1142
  try {
1177
- if (!fs3.existsSync(dir)) {
1178
- fs3.mkdirSync(dir, { recursive: true });
1143
+ if (!fs2.existsSync(dir)) {
1144
+ fs2.mkdirSync(dir, { recursive: true });
1179
1145
  }
1180
- if (!fs3.existsSync(filePath)) {
1181
- fs3.writeFileSync(filePath, "");
1146
+ if (!fs2.existsSync(filePath)) {
1147
+ fs2.writeFileSync(filePath, "");
1182
1148
  console.log(`\u2705 SQLite database created at "${filePath}"`);
1183
1149
  } else {
1184
1150
  console.log(`\u26A0\uFE0F SQLite database already exists at "${filePath}"`);
@@ -1191,20 +1157,20 @@ var SqliteAdapter = {
1191
1157
  async drop(url) {
1192
1158
  const filePath = parseSqliteUrl(url);
1193
1159
  try {
1194
- if (fs3.existsSync(filePath)) {
1195
- fs3.unlinkSync(filePath);
1160
+ if (fs2.existsSync(filePath)) {
1161
+ fs2.unlinkSync(filePath);
1196
1162
  console.log(`\u2705 SQLite database at "${filePath}" dropped successfully.`);
1197
1163
  } else {
1198
1164
  console.log(`\u26A0\uFE0F SQLite database does not exist at "${filePath}"`);
1199
1165
  }
1200
- if (fs3.existsSync(`${filePath}-journal`)) {
1201
- fs3.unlinkSync(`${filePath}-journal`);
1166
+ if (fs2.existsSync(`${filePath}-journal`)) {
1167
+ fs2.unlinkSync(`${filePath}-journal`);
1202
1168
  }
1203
- if (fs3.existsSync(`${filePath}-wal`)) {
1204
- fs3.unlinkSync(`${filePath}-wal`);
1169
+ if (fs2.existsSync(`${filePath}-wal`)) {
1170
+ fs2.unlinkSync(`${filePath}-wal`);
1205
1171
  }
1206
- if (fs3.existsSync(`${filePath}-shm`)) {
1207
- fs3.unlinkSync(`${filePath}-shm`);
1172
+ if (fs2.existsSync(`${filePath}-shm`)) {
1173
+ fs2.unlinkSync(`${filePath}-shm`);
1208
1174
  }
1209
1175
  } catch (error) {
1210
1176
  console.error("\u274C Error dropping SQLite database:", error);
@@ -1214,8 +1180,8 @@ var SqliteAdapter = {
1214
1180
  };
1215
1181
  function parseSqliteUrl(url) {
1216
1182
  let cleanPath = url.replace(/^file:/, "");
1217
- if (!path3.isAbsolute(cleanPath)) {
1218
- cleanPath = path3.resolve(process.cwd(), cleanPath);
1183
+ if (!path2.isAbsolute(cleanPath)) {
1184
+ cleanPath = path2.resolve(process.cwd(), cleanPath);
1219
1185
  }
1220
1186
  return cleanPath;
1221
1187
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prisma-flare",
3
- "version": "1.1.0",
3
+ "version": "1.1.1",
4
4
  "description": "Prisma utilities package with callback system and query builder for chained operations",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.js",
package/readme.md CHANGED
@@ -73,27 +73,49 @@ prisma-flare automatically detects your Prisma version at runtime and uses the a
73
73
  Replace your standard `PrismaClient` with `FlareClient` in your database setup file (e.g., `src/db.ts` or `src/lib/prisma.ts`).
74
74
 
75
75
  ```typescript
76
- // src/db.ts
77
- import { FlareClient, registerHooks } from 'prisma-flare';
76
+ // prisma/db.ts
77
+ import './callbacks'; // Import generated index to register all hooks
78
+ import { FlareClient } from 'prisma-flare';
78
79
 
79
- // Initialize hooks middleware and auto-load callbacks
80
- export const db = await registerHooks(new FlareClient());
80
+ export const db = new FlareClient();
81
81
  ```
82
82
 
83
- `registerHooks()` is async and:
84
- - Registers the hooks middleware (using the appropriate API for your Prisma version)
85
- - Automatically loads all callback files from `prisma/callbacks` (or your configured path)
86
- - Returns the extended client instance
83
+ `FlareClient` automatically attaches the callbacks middleware (using the appropriate API for your Prisma version). The callbacks import loads a generated barrel file that registers all your hooks - this pattern works in all environments (bundlers, Node.js, serverless, etc.).
87
84
 
88
- ### 2. Generate Query Classes
85
+ **With Prisma adapters:**
89
86
 
90
- Run the generator to create type-safe query classes for your specific schema.
87
+ ```typescript
88
+ import './callbacks';
89
+ import { PrismaPg } from '@prisma/adapter-pg';
90
+ import { FlareClient } from 'prisma-flare';
91
+
92
+ const adapter = new PrismaPg({ connectionString: process.env.DATABASE_URL });
93
+
94
+ export const db = new FlareClient({ adapter });
95
+ ```
96
+
97
+ **Disable callbacks middleware:**
98
+
99
+ ```typescript
100
+ import { FlareClient } from 'prisma-flare';
101
+
102
+ // If you don't use callbacks, disable the middleware for slightly less overhead
103
+ export const db = new FlareClient({ callbacks: false });
104
+ ```
105
+
106
+ ### 2. Generate Query Classes & Callbacks Index
107
+
108
+ Run the generator to create type-safe query classes and the callbacks barrel file.
91
109
 
92
110
  ```bash
93
111
  npx prisma-flare generate
94
112
  ```
95
113
 
96
- By default, this will look for your `db` instance in `src/db` and output queries to `src/models`.
114
+ This command:
115
+ - Generates query classes based on your `schema.prisma`
116
+ - Generates `prisma/callbacks/index.ts` that imports all your callback files
117
+
118
+ **Important:** Re-run this command after adding new callback files to update the index.
97
119
 
98
120
  ### 3. Configuration (Optional)
99
121
 
@@ -110,7 +132,7 @@ If your project structure is different, create a `prisma-flare.config.json` in y
110
132
 
111
133
  - `modelsPath`: Where to generate the query classes (defaults to `prisma/models`).
112
134
  - `dbPath`: Path to the file exporting your `db` instance (relative to project root, defaults to `prisma/db`).
113
- - `callbacksPath`: Directory containing your callback/hook files (defaults to `prisma/callbacks`). All `.ts`/`.js` files in this directory are automatically loaded when `registerHooks()` is called.
135
+ - `callbacksPath`: Directory containing your callback/hook files (defaults to `prisma/callbacks`). The generator creates an `index.ts` barrel file in this directory.
114
136
  - `envPath`: Path to your environment file (optional, defaults to `.env`).
115
137
  - `plurals`: Custom pluralization for model names (optional).
116
138
 
@@ -203,7 +225,7 @@ await DB.instance.transaction(async (tx) => {
203
225
 
204
226
  ### Callhooks & Middleware
205
227
 
206
- Define hooks to run logic before or after database operations. Create callback files in your callbacks directory (default: `prisma/callbacks`) and they'll be automatically loaded.
228
+ Define hooks to run logic before or after database operations. Create callback files in your callbacks directory (default: `prisma/callbacks`), then run `npx prisma-flare generate` to update the index.
207
229
 
208
230
  ```typescript
209
231
  // prisma/callbacks/user.ts
@@ -235,7 +257,7 @@ afterChange('post', 'published', async (oldValue, newValue, record) => {
235
257
  });
236
258
  ```
237
259
 
238
- All files in the callbacks directory are automatically imported when `registerHooks()` is called. No manual loading required.
260
+ After creating callback files, run `npx prisma-flare generate` to update the index. The generated `index.ts` imports all callbacks, which you then import in your db setup file.
239
261
 
240
262
  #### Hook Configuration
241
263
 
@@ -306,25 +328,22 @@ This prevents false positives when:
306
328
 
307
329
  #### Advanced Hook Registration
308
330
 
309
- For more control over hook registration, prisma-flare exports additional utilities:
331
+ For advanced use cases, prisma-flare exports lower-level utilities:
310
332
 
311
333
  ```typescript
312
334
  import {
313
- registerHooks, // Auto-detects Prisma version + auto-loads callbacks (recommended)
314
- registerHooksLegacy, // Force legacy $use API (Prisma ≤6 only, no auto-load)
335
+ registerHooksLegacy, // Force legacy $use API (Prisma ≤6 only)
315
336
  createHooksExtension, // Get raw extension for manual use
316
- loadCallbacks // Manually load callbacks from a custom path
337
+ loadCallbacks // Manually load callbacks at runtime (dev only)
317
338
  } from 'prisma-flare';
318
339
 
319
- // Option 1: Auto-detect with auto-loading (recommended)
320
- const db = await registerHooks(new FlareClient());
321
-
322
- // Option 2: Manual callback loading from custom path
340
+ // Manual extension on raw PrismaClient (advanced)
323
341
  import { PrismaClient } from '@prisma/client';
324
342
  const prisma = new PrismaClient().$extends(createHooksExtension(new PrismaClient()));
325
- await loadCallbacks('/custom/path/to/callbacks');
326
343
  ```
327
344
 
345
+ For most use cases, just use `new FlareClient()` which handles everything automatically.
346
+
328
347
  ## CLI Utilities
329
348
 
330
349
  Prisma Flare comes with a suite of CLI tools to manage your database workflow. It supports **PostgreSQL** and **SQLite** out of the box, and is extensible for other databases.