express-project-builder 1.0.38 → 1.0.39

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 CHANGED
@@ -228,43 +228,165 @@ my-test-project/
228
228
  - /src/app/builder/**PrismaQueryBuilder.ts** <br/>
229
229
  A fluent API for building complex SQL queries with Prisma. Simplifies dynamic query construction for search, filtering, sorting, pagination, and field selection in a chainable interface.
230
230
 
231
- ```typescript
232
- // In your controller/service:
233
- import PrismaQueryBuilder from "../../builder/PrismaQueryBuilder";
234
-
235
- // Extract query parameters from request (e.g., ?search=keyword&page=1&limit=10)
236
- const { page, limit, sort, search, fields, ...filters } = req.query;
237
-
238
- // Create a new query builder instance
239
- const docQuery = new PrismaQueryBuilder(YourModel.find(), req.query)
240
-
241
- // Search in specified text fields (e.g., name, description, category)
242
- .search(["name", "description", "category"])
243
-
244
- // Apply filters dynamically (e.g., status=active, category=tech)
245
- .filter()
246
-
247
- // Sort results (e.g., ?sort=name asc,sort=-createdAt desc)
248
- .sort()
249
-
250
- // Paginate results (e.g., ?page=1&limit=10)
251
- .paginate()
252
-
253
- // Select specific fields (e.g., ?fields=name,price,description)
254
- .fields();
255
-
256
- // Execute the query and get results
257
- const result = await docQuery.modelQuery;
258
-
259
- // Get pagination metadata (total count, page, limit, total pages)
260
- const meta = await docQuery.countTotal();
231
+ ```typescript
232
+ // ===============================
233
+ // Example Usage: PrismaQueryBuilder
234
+ // ===============================
235
+
236
+ import PrismaQueryBuilder from "../../builder/PrismaQueryBuilder";
237
+ import { prisma } from "../../shared/prisma";
238
+
239
+ // -------------------------------------------------
240
+ // Controller / Service Layer Example
241
+ // -------------------------------------------------
242
+
243
+ // Extract query parameters from request
244
+ // Example request:
245
+ // /api/docs?search=node&page=1&limit=10&sort=-createdAt&fields=name,price
246
+ const { page, limit, sort, search, fields, ...filters } = req.query;
247
+
248
+ /**
249
+ * Initialize Query Builder
250
+ *
251
+ * Parameters:
252
+ * 1. prisma.youModel -> Prisma model instance (table)
253
+ * 2. filters -> dynamic filters from query params
254
+ */
255
+ const docQuery = new PrismaQueryBuilder(prisma.youModel, filters)
256
+
257
+ /**
258
+ * setBaseQuery()
259
+ * ------------------------------------
260
+ * Adds default conditions that will always apply
261
+ * to the query.
262
+ *
263
+ * Example use cases:
264
+ * - Soft delete filtering
265
+ * - Tenant based filtering
266
+ * - Default status filtering
267
+ */
268
+ .setBaseQuery({
269
+ isDeleted: false,
270
+ })
271
+
272
+ /**
273
+ * setSecretFields()
274
+ * ------------------------------------
275
+ * Prevents sensitive fields from being returned
276
+ * in API responses.
277
+ *
278
+ * Example:
279
+ * password, tokens, internal flags etc.
280
+ */
281
+ .setSecretFields(["isDeleted", "password", "sensetiveFileds"])
282
+
283
+ /**
284
+ * search()
285
+ * ------------------------------------
286
+ * Enables text search across multiple fields.
287
+ *
288
+ * Example request:
289
+ * ?search=node
290
+ *
291
+ * This will search "node" in:
292
+ * name OR description OR category
293
+ */
294
+ .search(["name", "description", "category"])
295
+
296
+ /**
297
+ * filter()
298
+ * ------------------------------------
299
+ * Applies dynamic filters from query params.
300
+ *
301
+ * Example request:
302
+ * ?status=active&category=tech
303
+ *
304
+ * Automatically converts query params
305
+ * into Prisma "where" conditions.
306
+ */
307
+ .filter()
308
+
309
+ /**
310
+ * sort()
311
+ * ------------------------------------
312
+ * Enables sorting of results.
313
+ *
314
+ * Example requests:
315
+ * ?sort=name
316
+ * ?sort=-createdAt
317
+ *
318
+ * "-" indicates descending order.
319
+ */
320
+ .sort()
321
+
322
+ /**
323
+ * paginate()
324
+ * ------------------------------------
325
+ * Applies pagination.
326
+ *
327
+ * Example request:
328
+ * ?page=2&limit=10
329
+ *
330
+ * Converts into:
331
+ * skip + take (Prisma pagination)
332
+ */
333
+ .paginate()
334
+
335
+ /**
336
+ * fields()
337
+ * ------------------------------------
338
+ * Allows selecting specific fields.
339
+ *
340
+ * Example request:
341
+ * ?fields=name,price,description
342
+ *
343
+ * Only these fields will be returned
344
+ * in the response.
345
+ */
346
+ .fields()
347
+
348
+ /**
349
+ * include()
350
+ * ------------------------------------
351
+ * Allows joining related tables using
352
+ * Prisma's include/select functionality.
353
+ *
354
+ * Example:
355
+ * Including related user/profile data
356
+ */
357
+ .include({
358
+ table_name: {
359
+ select: {
360
+ row_1: true,
361
+ row_2: true,
362
+ },
363
+ },
364
+ });
261
365
 
262
- // Return the results and metadata from service
263
- return {
264
- result,
265
- meta,
266
- };
267
- ```
366
+ /**
367
+ * Execute the final query
368
+ */
369
+ const result = await docQuery.execute();
370
+
371
+ /**
372
+ * Get pagination metadata
373
+ *
374
+ * Returns:
375
+ * total records
376
+ * current page
377
+ * limit
378
+ * total pages
379
+ */
380
+ const meta = await docQuery.countTotal();
381
+
382
+ /**
383
+ * Final response format
384
+ */
385
+ return {
386
+ result,
387
+ meta,
388
+ };
389
+ ```
268
390
 
269
391
  - /src/**config/index.ts** <br/> Central configuration file that manages environment variables and application settings. This file provides a structured way to access environment variables throughout the application.
270
392
 
@@ -1 +1 @@
1
- {"version":3,"file":"create_QueryBuilder_Helpers.d.ts","sourceRoot":"","sources":["../../../../src/lib/src/builders/create_QueryBuilder_Helpers.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAGhD,eAAO,MAAM,2BAA2B,GACtC,aAAa,MAAM,EACnB,SAAS,QAAQ,KAChB,OAAO,CAAC,IAAI,CA0Sd,CAAC"}
1
+ {"version":3,"file":"create_QueryBuilder_Helpers.d.ts","sourceRoot":"","sources":["../../../../src/lib/src/builders/create_QueryBuilder_Helpers.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAGhD,eAAO,MAAM,2BAA2B,GACtC,aAAa,MAAM,EACnB,SAAS,QAAQ,KAChB,OAAO,CAAC,IAAI,CA6ed,CAAC"}
@@ -108,22 +108,54 @@ export default QueryBuilder;
108
108
  // Create Prisma QueryBuilder if PostgreSQL with Prisma is selected
109
109
  if (answers.database === "PostgreSQL with Prisma") {
110
110
  const prismaQueryBuilderTemplate = `/* eslint-disable @typescript-eslint/no-explicit-any */
111
- /**
112
- * Prisma Query Builder class for building complex queries with chaining methods
113
- * Similar pattern to the Mongoose QueryBuilder but adapted for Prisma
114
- */
115
111
  class PrismaQueryBuilder<T extends Record<string, any>> {
116
112
  private prismaModel: any
117
113
  private query: Record<string, unknown>
118
- private whereClause: any = {}
114
+ private baseWhereClause: any = {} // Priority query - cannot be overridden
115
+ private whereClause: any = {} // User filters
119
116
  private orderBy: any[] = []
120
117
  private selectFields: any = null
118
+ private includeRelations: any = null
121
119
  private skipValue: number | undefined
122
120
  private takeValue: number | undefined
121
+ private secretFields: string[] = [] // Fields that can NEVER be shown
122
+
123
123
  constructor(prismaModel: any, query: Record<string, unknown>) {
124
124
  this.prismaModel = prismaModel
125
125
  this.query = query
126
126
  }
127
+
128
+ /**
129
+ * Set base WHERE conditions that have PRIORITY and cannot be overridden
130
+ * These conditions are always applied regardless of user input
131
+ *
132
+ * @param baseWhere - Base WHERE conditions with priority
133
+ * @returns PrismaQueryBuilder instance for chaining
134
+ *
135
+ * @example
136
+ * .setBaseQuery({ ownerId: user.id, isDeleted: false })
137
+ * // User cannot override these conditions
138
+ */
139
+ setBaseQuery(baseWhere: Record<string, any>): this {
140
+ this.baseWhereClause = baseWhere
141
+ return this
142
+ }
143
+
144
+ /**
145
+ * Set fields that are SECRET and can NEVER be shown in output
146
+ * Even if user explicitly requests them via ?fields=password
147
+ *
148
+ * @param secretFields - Array of field names that must always be hidden
149
+ * @returns PrismaQueryBuilder instance for chaining
150
+ *
151
+ * @example
152
+ * .setSecretFields(['password', 'refreshToken', 'isDeleted'])
153
+ */
154
+ setSecretFields(secretFields: string[]): this {
155
+ this.secretFields = secretFields
156
+ return this
157
+ }
158
+
127
159
  /**
128
160
  * Add search functionality to the query
129
161
  * @param searchableFields - Array of fields to search in
@@ -132,37 +164,74 @@ class PrismaQueryBuilder<T extends Record<string, any>> {
132
164
  search(searchableFields: string[]): this {
133
165
  const searchTerm = this.query.search as string
134
166
  if (searchTerm) {
135
- this.whereClause = {
136
- ...this.whereClause,
137
- OR: searchableFields.map(field => ({
138
- [field]: {
139
- contains: searchTerm,
140
- mode: 'insensitive'
141
- }
142
- }))
167
+ const searchConditions = searchableFields.map(field => ({
168
+ [field]: {
169
+ contains: searchTerm,
170
+ mode: 'insensitive' as const
171
+ }
172
+ }))
173
+
174
+ if (Object.keys(this.whereClause).length > 0) {
175
+ this.whereClause = {
176
+ AND: [{ ...this.whereClause }, { OR: searchConditions }]
177
+ }
178
+ } else {
179
+ this.whereClause = {
180
+ OR: searchConditions
181
+ }
143
182
  }
144
183
  }
145
184
  return this
146
185
  }
186
+
147
187
  /**
148
- * Add filtering to the query
188
+ * Add filtering to the query (exact field = value matching)
189
+ * User filters are applied AFTER base query
149
190
  * @returns PrismaQueryBuilder instance for chaining
150
191
  */
151
192
  filter(): this {
152
193
  const queryObj = { ...this.query }
153
- const excludeFields = ['search', 'sort', 'page', 'limit', 'fields']
194
+
195
+ const excludeFields = [
196
+ 'search',
197
+ 'sort',
198
+ 'page',
199
+ 'limit',
200
+ 'fields',
201
+ 'field',
202
+ 'filelds',
203
+ 'include',
204
+ 'populate',
205
+ 'select'
206
+ ]
207
+
154
208
  excludeFields.forEach(el => delete queryObj[el])
155
- // Add the remaining query parameters to the where clause
209
+
210
+ // Remove any keys that match base query (prevent override)
211
+ Object.keys(this.baseWhereClause).forEach(key => {
212
+ delete queryObj[key]
213
+ })
214
+
156
215
  Object.entries(queryObj).forEach(([key, value]) => {
157
216
  if (value !== undefined && value !== null) {
158
- this.whereClause = {
159
- ...this.whereClause,
160
- [key]: value
217
+ let processedValue = value
218
+ if (value === 'true') processedValue = true
219
+ if (value === 'false') processedValue = false
220
+
221
+ if (this.whereClause.AND || this.whereClause.OR) {
222
+ const existingClause = { ...this.whereClause }
223
+ this.whereClause = {
224
+ AND: [existingClause, { [key]: processedValue }]
225
+ }
226
+ } else {
227
+ this.whereClause[key] = processedValue
161
228
  }
162
229
  }
163
230
  })
231
+
164
232
  return this
165
233
  }
234
+
166
235
  /**
167
236
  * Add sorting to the query
168
237
  * @returns PrismaQueryBuilder instance for chaining
@@ -179,11 +248,11 @@ class PrismaQueryBuilder<T extends Record<string, any>> {
179
248
  }
180
249
  })
181
250
  } else {
182
- // Default sort by createdAt in descending order
183
251
  this.orderBy = [{ createdAt: 'desc' }]
184
252
  }
185
253
  return this
186
254
  }
255
+
187
256
  /**
188
257
  * Add pagination to the query
189
258
  * @returns PrismaQueryBuilder instance for chaining
@@ -195,67 +264,171 @@ class PrismaQueryBuilder<T extends Record<string, any>> {
195
264
  this.takeValue = limit
196
265
  return this
197
266
  }
267
+
198
268
  /**
199
269
  * Field selection to include specific fields
270
+ * Secret fields are ALWAYS removed even if user requests them
271
+ *
200
272
  * @returns PrismaQueryBuilder instance for chaining
201
273
  */
202
274
  fields(): this {
203
- const fields = this.query.fields as string
275
+ const fields = (this.query.fields ||
276
+ this.query.field ||
277
+ this.query.filelds) as string
278
+
204
279
  if (fields) {
205
- const fieldArray = fields.split(',')
206
- this.selectFields = fieldArray.reduce((acc, field) => {
207
- // Skip the __v field which doesn't exist in Prisma
208
- if (field !== '__v') {
280
+ const fieldArray = fields.split(',').map(f => f.trim())
281
+
282
+ // Filter out secret fields - user cannot request them
283
+ const allowedFields = fieldArray.filter(
284
+ field =>
285
+ !this.secretFields.includes(field) && field !== '__v' && field !== ''
286
+ )
287
+
288
+ if (allowedFields.length > 0) {
289
+ this.selectFields = allowedFields.reduce((acc, field) => {
209
290
  acc[field] = true
210
- }
211
- return acc
212
- }, {} as any)
291
+ return acc
292
+ }, {} as any)
293
+ }
294
+ }
295
+
296
+ return this
297
+ }
298
+
299
+ /**
300
+ * Add relations to include with automatic secret field removal
301
+ *
302
+ * @param relations - Object defining which relations to include
303
+ * @param nestedSecretFields - Secret fields for nested relations
304
+ * @returns PrismaQueryBuilder instance for chaining
305
+ *
306
+ * @example
307
+ * .include(
308
+ * {
309
+ * owner: { select: { id: true, name: true, phone: true } },
310
+ * posts: true
311
+ * },
312
+ * {
313
+ * owner: ['password', 'refreshToken'],
314
+ * posts: ['isDeleted', 'internalNotes']
315
+ * }
316
+ * )
317
+ */
318
+ include(relations: any, nestedSecretFields?: Record<string, string[]>): this {
319
+ if (typeof relations === 'object' && relations !== null) {
320
+ // Process relations and apply secret field filtering
321
+ const processedRelations = { ...relations }
322
+
323
+ if (nestedSecretFields) {
324
+ Object.keys(processedRelations).forEach(relationName => {
325
+ const relation = processedRelations[relationName]
326
+ const secretFieldsForRelation = nestedSecretFields[relationName]
327
+
328
+ if (secretFieldsForRelation && relation !== true) {
329
+ // If relation has select, filter out secret fields
330
+ if (relation.select) {
331
+ secretFieldsForRelation.forEach(field => {
332
+ delete relation.select[field]
333
+ })
334
+ }
335
+ }
336
+ })
337
+ }
338
+
339
+ this.includeRelations = processedRelations
213
340
  }
214
341
  return this
215
342
  }
343
+
216
344
  /**
217
- * Execute the query and return results with metadata
218
- * @returns Object with data and pagination metadata
345
+ * Execute the query and return data
346
+ * Combines base query with user filters
347
+ * Removes secret fields from output
348
+ *
349
+ * @returns Array of data
219
350
  */
220
- async execute(): Promise<{
221
- data: T[]
222
- meta: {
223
- page: number
224
- limit: number
225
- totalData: number
226
- totalPage: number
351
+ async execute(): Promise<T[]> {
352
+ // Combine base query (priority) with user filters
353
+ let finalWhereClause: any = {}
354
+
355
+ if (
356
+ Object.keys(this.baseWhereClause).length > 0 &&
357
+ Object.keys(this.whereClause).length > 0
358
+ ) {
359
+ // Both base and user filters exist - combine with AND
360
+ finalWhereClause = {
361
+ AND: [this.baseWhereClause, this.whereClause]
362
+ }
363
+ } else if (Object.keys(this.baseWhereClause).length > 0) {
364
+ // Only base query
365
+ finalWhereClause = this.baseWhereClause
366
+ } else if (Object.keys(this.whereClause).length > 0) {
367
+ // Only user filters
368
+ finalWhereClause = this.whereClause
227
369
  }
228
- }> {
229
- const page = Number(this.query.page) || 1
230
- const limit = Number(this.query.limit) || 10
231
- // Build the query parameters
370
+
232
371
  const queryOptions: any = {
233
- where: this.whereClause,
372
+ where:
373
+ Object.keys(finalWhereClause).length > 0 ? finalWhereClause : undefined,
234
374
  orderBy: this.orderBy.length > 0 ? this.orderBy : undefined,
235
375
  skip: this.skipValue,
236
376
  take: this.takeValue
237
377
  }
238
- // Add select if specified
239
- if (this.selectFields) {
378
+
379
+ if (this.selectFields && !this.includeRelations) {
240
380
  queryOptions.select = this.selectFields
241
381
  }
242
- // Get total count
243
- const totalData = await this.prismaModel.count({ where: this.whereClause })
244
- const totalPage = Math.ceil(totalData / limit)
245
- // Get data
246
- const data = await this.prismaModel.findMany(queryOptions)
247
- return {
248
- data,
249
- meta: {
250
- page,
251
- limit,
252
- totalData,
253
- totalPage
254
- }
382
+
383
+ if (this.includeRelations) {
384
+ queryOptions.include = this.includeRelations
385
+ }
386
+
387
+ let data = await this.prismaModel.findMany(queryOptions)
388
+
389
+ // Remove secret fields from output (post-processing for security)
390
+ if (this.secretFields.length > 0) {
391
+ data = this.removeSecretFields(data, this.secretFields)
255
392
  }
393
+
394
+ return data
395
+ }
396
+
397
+ /**
398
+ * Remove secret fields from data recursively (handles nested objects)
399
+ * @param data - Data to process
400
+ * @param secretFields - Fields to remove
401
+ * @returns Cleaned data
402
+ */
403
+ private removeSecretFields(data: any, secretFields: string[]): any {
404
+ if (Array.isArray(data)) {
405
+ return data.map(item => this.removeSecretFields(item, secretFields))
406
+ }
407
+
408
+ // ✅ IMPORTANT: Preserve Date objects
409
+ if (data instanceof Date) {
410
+ return data
411
+ }
412
+
413
+ if (data && typeof data === 'object') {
414
+ const cleaned: any = {}
415
+
416
+ Object.keys(data).forEach(key => {
417
+ if (!secretFields.includes(key)) {
418
+ cleaned[key] = this.removeSecretFields(data[key], secretFields)
419
+ }
420
+ })
421
+
422
+ return cleaned
423
+ }
424
+
425
+ return data
256
426
  }
427
+
257
428
  /**
258
- * Get total count and pagination metadata without fetching data
429
+ * Get pagination metadata
430
+ * Uses combined WHERE clause (base + user filters)
431
+ *
259
432
  * @returns Object with pagination metadata
260
433
  */
261
434
  async countTotal(): Promise<{
@@ -266,8 +439,29 @@ class PrismaQueryBuilder<T extends Record<string, any>> {
266
439
  }> {
267
440
  const page = Number(this.query.page) || 1
268
441
  const limit = Number(this.query.limit) || 10
269
- const totalData = await this.prismaModel.count({ where: this.whereClause })
442
+
443
+ // Combine base query with user filters for counting
444
+ let finalWhereClause: any = {}
445
+
446
+ if (
447
+ Object.keys(this.baseWhereClause).length > 0 &&
448
+ Object.keys(this.whereClause).length > 0
449
+ ) {
450
+ finalWhereClause = {
451
+ AND: [this.baseWhereClause, this.whereClause]
452
+ }
453
+ } else if (Object.keys(this.baseWhereClause).length > 0) {
454
+ finalWhereClause = this.baseWhereClause
455
+ } else if (Object.keys(this.whereClause).length > 0) {
456
+ finalWhereClause = this.whereClause
457
+ }
458
+
459
+ const totalData = await this.prismaModel.count({
460
+ where:
461
+ Object.keys(finalWhereClause).length > 0 ? finalWhereClause : undefined
462
+ })
270
463
  const totalPage = Math.ceil(totalData / limit)
464
+
271
465
  return {
272
466
  page,
273
467
  limit,
@@ -276,6 +470,7 @@ class PrismaQueryBuilder<T extends Record<string, any>> {
276
470
  }
277
471
  }
278
472
  }
473
+
279
474
  export default PrismaQueryBuilder
280
475
  `;
281
476
  await createFile(path.join(projectPath, "src/app/builder", "PrismaQueryBuilder.ts"), prismaQueryBuilderTemplate);
@@ -1 +1 @@
1
- {"version":3,"file":"create_QueryBuilder_Helpers.js","sourceRoot":"","sources":["../../../../src/lib/src/builders/create_QueryBuilder_Helpers.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,mDAAmD;AACnD,MAAM,CAAC,MAAM,2BAA2B,GAAG,KAAK,EAC9C,WAAmB,EACnB,OAAiB,EACF,EAAE;IACjB,IAAI,CAAC;QACH,qDAAqD;QACrD,IAAI,OAAO,CAAC,QAAQ,KAAK,uBAAuB,EAAE,CAAC;YACjD,MAAM,yBAAyB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgGvC,CAAC;YACI,MAAM,UAAU,CACd,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,iBAAiB,EAAE,yBAAyB,CAAC,EACpE,yBAAyB,CAC1B,CAAC;QACJ,CAAC;QAED,mEAAmE;QACnE,IAAI,OAAO,CAAC,QAAQ,KAAK,wBAAwB,EAAE,CAAC;YAClD,MAAM,0BAA0B,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0KxC,CAAC;YACI,MAAM,UAAU,CACd,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,iBAAiB,EAAE,uBAAuB,CAAC,EAClE,0BAA0B,CAC3B,CAAC;QACJ,CAAC;QAED,gDAAgD;QAChD,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,KAAK,CAAC,kDAAkD,CAAC,CAChE,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,wCAAwC;QACxC,OAAO,CAAC,KAAK,CACX,KAAK,CAAC,GAAG,CAAC,6CAA6C,CAAC,EACxD,GAAG,CACJ,CAAC;QACF,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC,CAAC"}
1
+ {"version":3,"file":"create_QueryBuilder_Helpers.js","sourceRoot":"","sources":["../../../../src/lib/src/builders/create_QueryBuilder_Helpers.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,mDAAmD;AACnD,MAAM,CAAC,MAAM,2BAA2B,GAAG,KAAK,EAC9C,WAAmB,EACnB,OAAiB,EACF,EAAE;IACjB,IAAI,CAAC;QACH,qDAAqD;QACrD,IAAI,OAAO,CAAC,QAAQ,KAAK,uBAAuB,EAAE,CAAC;YACjD,MAAM,yBAAyB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgGvC,CAAC;YACI,MAAM,UAAU,CACd,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,iBAAiB,EAAE,yBAAyB,CAAC,EACpE,yBAAyB,CAC1B,CAAC;QACJ,CAAC;QAED,mEAAmE;QACnE,IAAI,OAAO,CAAC,QAAQ,KAAK,wBAAwB,EAAE,CAAC;YAClD,MAAM,0BAA0B,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6WxC,CAAC;YACI,MAAM,UAAU,CACd,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,iBAAiB,EAAE,uBAAuB,CAAC,EAClE,0BAA0B,CAC3B,CAAC;QACJ,CAAC;QAED,gDAAgD;QAChD,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,KAAK,CAAC,kDAAkD,CAAC,CAChE,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,wCAAwC;QACxC,OAAO,CAAC,KAAK,CACX,KAAK,CAAC,GAAG,CAAC,6CAA6C,CAAC,EACxD,GAAG,CACJ,CAAC;QACF,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "express-project-builder",
3
- "version": "1.0.38",
3
+ "version": "1.0.39",
4
4
  "description": "A powerful and professional Express.js project generator CLI that instantly scaffolds a production-ready backend with TypeScript, modular architecture, and built-in support for MongoDB (Mongoose) or PostgreSQL (Prisma). Includes authentication, error handling, rate limiting, file upload, caching, and utility functions—so you can focus on building features instead of boilerplate. Perfect for kickstarting your next Express.js API project with best practices and modern tools.",
5
5
  "type": "module",
6
6
  "main": "dist/bin/index.js",