tsledge 0.1.30 → 0.1.32

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.
@@ -1,37 +1,59 @@
1
- // tests/main.ts
2
- import dotenv from "dotenv";
3
-
4
- // src/db/mongodb.ts
5
- import mongoose from "mongoose";
6
-
7
- // src/exitCodes.ts
8
- var EXIT_CODE_GENERAL_ERROR = 1;
9
- var EXIT_CODE_INVALID_CONFIG = 2;
10
-
11
- // src/utils/date.ts
12
- function getCurrentDateString() {
13
- let date = /* @__PURE__ */ new Date();
14
- return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}`;
15
- }
16
-
17
- // src/utils/validation.ts
18
- function validateString(value, fallback = null) {
19
- if (value !== void 0 && value !== null && value !== "" && value !== "undefined" && value !== "null") {
20
- return value;
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __export = (target, all) => {
6
+ for (var name in all)
7
+ __defProp(target, name, { get: all[name], enumerable: true });
8
+ };
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
21
14
  }
22
- return fallback;
23
- }
15
+ return to;
16
+ };
17
+ var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
24
18
 
25
- // src/utils/env.ts
26
- var JwtSecret = process.env.JWT_SECRET || "secret";
27
- var JwtRefreshSecret = process.env.JWT_REFRESH_SECRET || "refresh_secret";
19
+ // tests/main.ts
20
+ import dotenv from "dotenv";
28
21
 
29
- // src/utils/encoding.ts
30
- function encodeToBase64(obj) {
31
- return btoa(encodeURIComponent(JSON.stringify(obj)));
32
- }
22
+ // src/index.ts
23
+ var src_exports = {};
24
+ __export(src_exports, {
25
+ AuthTokenBlocklistModel: () => AuthTokenBlocklistModel,
26
+ AuthUserModel: () => AuthUserModel,
27
+ FluentPatternHandler: () => FluentPatternHandler,
28
+ JoinRelation: () => JoinRelation,
29
+ JwtRefreshSecret: () => JwtRefreshSecret,
30
+ JwtSecret: () => JwtSecret,
31
+ QueryBuilder: () => QueryBuilder,
32
+ authLogin: () => authLogin,
33
+ authLogout: () => authLogout,
34
+ authRefresh: () => authRefresh,
35
+ authRegister: () => authRegister,
36
+ connectMongoDB: () => connectMongoDB,
37
+ createApp: () => createApp,
38
+ diskFileUpload: () => diskFileUpload,
39
+ errorLogger: () => errorLogger,
40
+ fluentRequestQueryAttributes: () => fluentRequestQueryAttributes,
41
+ insertCollectionRelations: () => insertCollectionRelations,
42
+ isDebug: () => isDebug,
43
+ jwtRefreshRequired: () => jwtRefreshRequired,
44
+ jwtRequired: () => jwtRequired,
45
+ memoryFileUpload: () => memoryFileUpload,
46
+ mergeCollectionRelations: () => mergeCollectionRelations,
47
+ requestLogger: () => requestLogger,
48
+ socketToken: () => socketToken,
49
+ verifyToken: () => verifyToken
50
+ });
51
+ __reExport(src_exports, tsledge_core_star);
52
+ import * as tsledge_core_star from "tsledge-core";
33
53
 
34
54
  // src/db/mongodb.ts
55
+ import mongoose from "mongoose";
56
+ import { EXIT_CODE_GENERAL_ERROR, EXIT_CODE_INVALID_CONFIG, getCurrentDateString } from "tsledge-core";
35
57
  async function connectMongoDB(uri) {
36
58
  if (uri == null || uri == void 0 || uri.length == 0) {
37
59
  console.error(`\u{1F6D1} [${getCurrentDateString()}] Error: MongoDB URI is not provided`);
@@ -50,24 +72,27 @@ async function connectMongoDB(uri) {
50
72
  import multer from "multer";
51
73
  import path from "node:path";
52
74
  import fs from "node:fs";
53
- var uploadDir = path.resolve(process.cwd(), "src", "files");
54
- fs.mkdirSync(uploadDir, { recursive: true });
55
75
  var sanitizeFilename = (name) => name.replace(/[^a-zA-Z0-9._-]/g, "_");
56
- var diskStorage = multer.diskStorage({
57
- destination: (_req, _file, next) => next(null, uploadDir),
58
- filename: (_req, file, next) => {
59
- const ext = path.extname(file.originalname);
60
- const base = path.basename(file.originalname, ext);
61
- const safe = sanitizeFilename(base);
62
- const unique = Date.now() + "-" + Math.round(Math.random() * 1e9);
63
- next(null, `${safe}-${unique}${ext}`);
64
- }
65
- });
76
+ var diskStorage = (directory = "files") => {
77
+ let uploadDir = path.resolve(process.cwd(), "src", directory);
78
+ fs.mkdirSync(uploadDir, { recursive: true });
79
+ return multer.diskStorage({
80
+ destination: (_req, _file, next) => next(null, uploadDir),
81
+ filename: (_req, file, next) => {
82
+ const ext = path.extname(file.originalname);
83
+ const base = path.basename(file.originalname, ext);
84
+ const safe = sanitizeFilename(base);
85
+ const unique = Date.now() + "-" + Math.round(Math.random() * 1e9);
86
+ next(null, `${safe}-${unique}${ext}`);
87
+ }
88
+ });
89
+ };
66
90
  var memoryStorage = multer.memoryStorage();
67
- var diskFileUpload = multer({ storage: diskStorage });
91
+ var diskFileUpload = (directory = "files") => multer({ storage: diskStorage(directory) });
68
92
  var memoryFileUpload = multer({ storage: memoryStorage });
69
93
 
70
94
  // src/middleware/logger.ts
95
+ import { getCurrentDateString as getCurrentDateString2 } from "tsledge-core";
71
96
  function requestLogger(req, res, next) {
72
97
  res.on("finish", () => {
73
98
  let emoji = "";
@@ -78,19 +103,99 @@ function requestLogger(req, res, next) {
78
103
  else if (res.statusCode >= 400 && res.statusCode < 500) emoji = "\u26A0\uFE0F";
79
104
  else if (res.statusCode >= 500) emoji = "\u{1F525}";
80
105
  console.log(
81
- `${emoji} [${getCurrentDateString()}] ${req.method} ${req.originalUrl} - ${res.statusCode}`
106
+ `${emoji} [${getCurrentDateString2()}] ${req.method} ${req.originalUrl} - ${res.statusCode}`
82
107
  );
83
108
  });
84
109
  next();
85
110
  }
86
111
  function errorLogger(err, req, res, next) {
87
- console.error(`\u{1F6D1} [${getCurrentDateString()}] Error in ${req.method} ${req.originalUrl}:`, err);
112
+ console.error(`\u{1F6D1} [${getCurrentDateString2()}] Error in ${req.method} ${req.originalUrl}:`, err);
88
113
  res.status(500).json();
89
114
  }
90
115
 
91
116
  // src/middleware/authentication/session.ts
92
117
  import express from "express";
93
118
  import bcrypt from "bcrypt";
119
+
120
+ // src/utils/mongo-relation.ts
121
+ function insertCollectionRelations(model, relations, compareFunc, validateFunc = void 0) {
122
+ if (relations == void 0) {
123
+ return;
124
+ }
125
+ let relationStack = [];
126
+ for (let relation of relations) {
127
+ if (validateFunc) {
128
+ relation = validateFunc(relation);
129
+ }
130
+ let inStack = false;
131
+ for (let duplicateRelationCheck of relationStack) {
132
+ if (compareFunc(relation, duplicateRelationCheck)) {
133
+ inStack = true;
134
+ }
135
+ }
136
+ if (!inStack) {
137
+ relationStack.push(relation);
138
+ }
139
+ }
140
+ if (relationStack.length > 0) {
141
+ model.insertMany(relationStack);
142
+ }
143
+ }
144
+ async function mergeCollectionRelations(model, relationsToMerge, match, compareFunc, validateFunc) {
145
+ const relationStack = [];
146
+ if (relationsToMerge != null) {
147
+ for (const relation of relationsToMerge) {
148
+ const validatedRelation = validateFunc(relation);
149
+ if (!relationStack.some(
150
+ (duplicateRelationCheck) => compareFunc(validatedRelation, duplicateRelationCheck)
151
+ )) {
152
+ relationStack.push(validatedRelation);
153
+ }
154
+ }
155
+ }
156
+ if (relationStack.length === 0) {
157
+ await model.deleteMany(match);
158
+ } else {
159
+ const existingRels = await model.find(match).lean();
160
+ const toRemoveRels = [];
161
+ for (const rel of existingRels) {
162
+ if (!relationStack.some((relationFromStack) => compareFunc(rel, relationFromStack))) {
163
+ toRemoveRels.push(rel);
164
+ }
165
+ }
166
+ const toCreateRels = [];
167
+ for (const relationFromStack of relationStack) {
168
+ if (!existingRels.some((rel) => compareFunc(rel, relationFromStack))) {
169
+ toCreateRels.push(relationFromStack);
170
+ }
171
+ }
172
+ if (toCreateRels.length > 0) {
173
+ await model.insertMany(toCreateRels);
174
+ }
175
+ if (toRemoveRels.length > 0) {
176
+ const idsToRemove = toRemoveRels.map((rel) => rel._id);
177
+ await model.deleteMany({ _id: { $in: idsToRemove } });
178
+ }
179
+ }
180
+ }
181
+
182
+ // src/utils/env.ts
183
+ var JwtSecret = process.env.JWT_SECRET || "secret";
184
+ var JwtRefreshSecret = process.env.JWT_REFRESH_SECRET || "refresh_secret";
185
+ function isDebug(func = void 0) {
186
+ const dbg = process.env.DEBUG;
187
+ if (dbg !== void 0) {
188
+ const v = dbg.toString().trim().toLowerCase();
189
+ let validation = v === "1" || v === "true" || v === "yes" || v === "on";
190
+ if (validation && func != void 0) {
191
+ func();
192
+ }
193
+ return validation;
194
+ }
195
+ return false;
196
+ }
197
+
198
+ // src/middleware/authentication/session.ts
94
199
  import jwt2 from "jsonwebtoken";
95
200
 
96
201
  // src/middleware/authentication/validation.ts
@@ -198,7 +303,7 @@ async function validateJwt(req, res, next, jwtSecret) {
198
303
  console.log("[WARN] JWT token for blocked user");
199
304
  return res.sendStatus(FORBIDDEN);
200
305
  }
201
- res.locals.user = result.payload;
306
+ res.locals.authUserPayload = result.payload;
202
307
  res.locals.token = token;
203
308
  next();
204
309
  } catch (err) {
@@ -206,8 +311,30 @@ async function validateJwt(req, res, next, jwtSecret) {
206
311
  return res.sendStatus(FORBIDDEN);
207
312
  }
208
313
  }
314
+ async function socketToken(_socket, _next) {
315
+ const token = _socket.handshake.auth?.token;
316
+ if (!token) {
317
+ return _next();
318
+ }
319
+ try {
320
+ const verificationResult = await verifyToken(token, JwtSecret);
321
+ const isValidChar = verificationResult.isTokenValid && !verificationResult.isTokenExpired ? "\u{1F7E2}" : "\u{1F534}";
322
+ console.log(`${isValidChar} Socket verification result: ${JSON.stringify(verificationResult)}`);
323
+ if (!verificationResult.isTokenValid) {
324
+ if (verificationResult.isTokenExpired) {
325
+ return _next(new Error("expired_token"));
326
+ }
327
+ return _next(new Error("invalid_token"));
328
+ }
329
+ _socket.user = verificationResult.payload;
330
+ _next();
331
+ } catch (err) {
332
+ return _next(new Error("invalid_token"));
333
+ }
334
+ }
209
335
 
210
336
  // src/middleware/authentication/session.ts
337
+ import { encodeToBase64, validateString } from "tsledge-core";
211
338
  var router = express.Router();
212
339
  var FORBIDDEN2 = 403;
213
340
  var BAD_REQUEST = 400;
@@ -245,12 +372,14 @@ async function generateCredentials(auth) {
245
372
  async function authRegister(req, res, next) {
246
373
  let { identifier = void 0, secret = void 0 } = req.body || {};
247
374
  if (!identifier || !secret) {
248
- return res.sendStatus(FORBIDDEN2);
375
+ res.sendStatus(FORBIDDEN2);
376
+ return;
249
377
  }
250
378
  identifier = identifier.toLowerCase();
251
379
  let user = await AuthUserModel.findOne({ identifier });
252
380
  if (user) {
253
- return res.sendStatus(BAD_REQUEST);
381
+ res.sendStatus(BAD_REQUEST);
382
+ return;
254
383
  }
255
384
  res.locals.authUser = new AuthUserModel({
256
385
  identifier,
@@ -261,32 +390,47 @@ async function authRegister(req, res, next) {
261
390
  async function authLogin(req, res, next) {
262
391
  let { identifier = void 0, secret = void 0 } = req.body || {};
263
392
  if (!identifier || !secret) {
264
- return res.sendStatus(FORBIDDEN2);
393
+ res.sendStatus(FORBIDDEN2);
394
+ return;
265
395
  }
266
396
  identifier = identifier.toLowerCase();
267
397
  let user = await AuthUserModel.findOne({ identifier }).select("+secretHash");
268
398
  if (!user || !user.secretHash) {
269
- return res.sendStatus(BAD_REQUEST);
399
+ res.sendStatus(BAD_REQUEST);
400
+ return;
270
401
  }
271
402
  if (user.blockedSince) {
272
- return res.sendStatus(FORBIDDEN2);
403
+ res.sendStatus(FORBIDDEN2);
404
+ return;
273
405
  }
274
406
  let isMatch = await bcrypt.compare(secret, user.secretHash);
275
407
  if (!isMatch) {
276
- return res.sendStatus(BAD_REQUEST);
408
+ res.sendStatus(BAD_REQUEST);
409
+ return;
277
410
  }
278
411
  let credentials = await generateCredentials(user);
279
412
  if (!credentials) {
280
- return res.sendStatus(BAD_REQUEST);
413
+ res.sendStatus(BAD_REQUEST);
414
+ return;
281
415
  }
282
416
  res.locals.credentials = credentials;
417
+ res.locals.authUser = user;
283
418
  next();
284
419
  }
285
420
  async function authLogout(req, res, next) {
286
421
  await jwtRefreshRequired(req, res, async () => {
422
+ let authUserPayload = res.locals.authUserPayload;
423
+ let user = await AuthUserModel.findOne({ identifier: authUserPayload.identifier }).select(
424
+ "+secretHash"
425
+ );
426
+ if (!user || !user.secretHash) {
427
+ res.sendStatus(BAD_REQUEST);
428
+ return;
429
+ }
287
430
  const refreshToken = res.locals.token;
288
431
  if (!refreshToken) {
289
- return res.sendStatus(BAD_REQUEST);
432
+ res.sendStatus(BAD_REQUEST);
433
+ return;
290
434
  }
291
435
  const decoded = jwt2.decode(refreshToken);
292
436
  const jti = decoded?.jti;
@@ -307,53 +451,66 @@ async function authLogout(req, res, next) {
307
451
  }
308
452
  }
309
453
  }
454
+ res.locals.authUser = user;
310
455
  next();
311
456
  });
312
457
  }
313
458
  async function authRefresh(req, res, next) {
314
459
  await jwtRefreshRequired(req, res, async () => {
315
- });
316
- const refreshToken = res.locals.token;
317
- if (!refreshToken) {
318
- return res.sendStatus(BAD_REQUEST);
319
- }
320
- try {
321
- const decoded = jwt2.decode(refreshToken);
322
- const jti = decoded?.jti;
323
- if (jti) {
324
- const existingBlock = await AuthTokenBlocklistModel.findOne({ jti });
325
- if (!existingBlock) {
326
- await new AuthTokenBlocklistModel({ jti }).save();
327
- }
460
+ let authUserPayload = res.locals.authUserPayload;
461
+ let user = await AuthUserModel.findOne({ identifier: authUserPayload.identifier }).select(
462
+ "+secretHash"
463
+ );
464
+ if (!user || !user.secretHash) {
465
+ res.sendStatus(BAD_REQUEST);
466
+ return;
328
467
  }
329
- let accessToken = validateString(req.body?.access_token);
330
- if (accessToken) {
331
- const accessTokenDecoded = jwt2.decode(accessToken);
332
- let accessTokenJti = accessTokenDecoded?.jti;
333
- if (accessTokenJti) {
334
- const existing = await AuthTokenBlocklistModel.findOne({
335
- jti: accessTokenJti
336
- });
337
- if (!existing) {
338
- await new AuthTokenBlocklistModel({ jti: accessTokenJti }).save();
468
+ const refreshToken = res.locals.token;
469
+ if (!refreshToken) {
470
+ res.sendStatus(BAD_REQUEST);
471
+ return;
472
+ }
473
+ try {
474
+ const decoded = jwt2.decode(refreshToken);
475
+ const jti = decoded?.jti;
476
+ if (jti) {
477
+ const existingBlock = await AuthTokenBlocklistModel.findOne({ jti });
478
+ if (!existingBlock) {
479
+ await new AuthTokenBlocklistModel({ jti }).save();
339
480
  }
340
481
  }
482
+ let accessToken = validateString(req.body?.access_token);
483
+ if (accessToken) {
484
+ const accessTokenDecoded = jwt2.decode(accessToken);
485
+ let accessTokenJti = accessTokenDecoded?.jti;
486
+ if (accessTokenJti) {
487
+ const existing = await AuthTokenBlocklistModel.findOne({
488
+ jti: accessTokenJti
489
+ });
490
+ if (!existing) {
491
+ await new AuthTokenBlocklistModel({ jti: accessTokenJti }).save();
492
+ }
493
+ }
494
+ }
495
+ const payload = jwt2.verify(refreshToken, JwtRefreshSecret);
496
+ let credentials = await generateCredentials(payload);
497
+ if (!credentials) {
498
+ res.sendStatus(BAD_REQUEST);
499
+ return;
500
+ }
501
+ res.locals.authUser = user;
502
+ res.locals.credentials = credentials;
503
+ next();
504
+ } catch (err) {
505
+ console.log("[WARN] refreshing JWT:", err);
506
+ res.sendStatus(BAD_REQUEST);
507
+ return;
341
508
  }
342
- const payload = jwt2.verify(refreshToken, JwtRefreshSecret);
343
- let credentials = await generateCredentials(payload);
344
- if (!credentials) {
345
- return res.sendStatus(BAD_REQUEST);
346
- }
347
- res.locals.credentials = credentials;
348
- next();
349
- } catch (err) {
350
- console.log("[WARN] refreshing JWT:", err);
351
- return res.sendStatus(BAD_REQUEST);
352
- }
509
+ });
353
510
  }
354
511
 
355
512
  // src/fluent-interface/fluent-pattern-handler.ts
356
- import mongoose5 from "mongoose";
513
+ import mongoose4 from "mongoose";
357
514
 
358
515
  // src/fluent-interface/types.ts
359
516
  var fluentRequestQueryAttributes = {
@@ -366,34 +523,180 @@ var fluentRequestQueryAttributes = {
366
523
  excluded: ""
367
524
  };
368
525
 
369
- // src/core/query-builder.ts
370
- import mongoose4 from "mongoose";
371
-
372
- // src/core/types.ts
373
- var Codec = class {
374
- constructor(content, code = 202) {
375
- this.content = content;
376
- this.returnCode = code;
526
+ // src/fluent-interface/fluent-pattern-handler.ts
527
+ import { Codec } from "tsledge-core";
528
+ var FluentPatternHandler = class _FluentPatternHandler {
529
+ /**
530
+ * Constructor for FluentPatternHandler.
531
+ * @param execMiddleware - Optional array of middleware functions to be executed before the main query execution in the exec method.
532
+ */
533
+ constructor(execMiddleware = []) {
534
+ /**
535
+ * Array of middleware functions to be executed before the main query execution in the exec method. Each function receives the execution parameters and can modify them as needed.
536
+ */
537
+ this._execMiddlewareFunctions = [];
538
+ if (_FluentPatternHandler._singleton) {
539
+ throw new Error(
540
+ "FluentPatternHandler is a singleton class. Use FluentPatternHandler.getInstance() to access the instance."
541
+ );
542
+ }
543
+ this._execMiddlewareFunctions = execMiddleware;
544
+ _FluentPatternHandler._singleton = this;
377
545
  }
378
- sendToClient(res) {
379
- if (this.content == null) {
380
- res.status(404).json({});
546
+ /**
547
+ * Initializes the singleton instance of FluentPatternHandler with the provided options.
548
+ * @param execMiddleware - Optional array of middleware functions to be executed before the main query execution in the exec method.
549
+ * @returns Singleton instance of FluentPatternHandler.
550
+ */
551
+ static init(execMiddleware = []) {
552
+ if (_FluentPatternHandler._singleton != void 0) {
553
+ throw new Error("FluentPatternHandler is already initialized");
381
554
  }
382
- res.status(this.returnCode).json(this.content);
555
+ _FluentPatternHandler._singleton = new _FluentPatternHandler(execMiddleware);
556
+ return _FluentPatternHandler._singleton;
383
557
  }
384
- is1xx() {
385
- return this.returnCode >= 100 && this.returnCode <= 199;
558
+ /**
559
+ * Returns the singleton instance of FluentPatternHandler.
560
+ * @returns Singleton instance of FluentPatternHandler.
561
+ */
562
+ static getInstance() {
563
+ if (_FluentPatternHandler._singleton == void 0) {
564
+ throw new Error(
565
+ "FluentPatternHandler instance has not been created yet. Please create an instance before calling getInstance()."
566
+ );
567
+ }
568
+ return _FluentPatternHandler._singleton;
386
569
  }
387
- is2xx() {
388
- return this.returnCode >= 200 && this.returnCode <= 299;
570
+ /**
571
+ * Parses and validates query parameters from the request.
572
+ * @param query - The query object from the request.
573
+ * @returns Parsed query parameters.
574
+ */
575
+ _parseFluentRequestQuery(query) {
576
+ const { filter, limit = "5", offset = "0", id, excluded: excludedJSON, ids: idsJSON } = query;
577
+ const queryKeys = Object.keys(fluentRequestQueryAttributes);
578
+ let filterFields = {};
579
+ for (const [key, value] of Object.entries(query)) {
580
+ if (queryKeys.includes(key)) continue;
581
+ if (value == void 0) continue;
582
+ try {
583
+ filterFields[key] = typeof value === "string" ? value : JSON.stringify(value);
584
+ } catch (e) {
585
+ filterFields[key] = String(value);
586
+ }
587
+ }
588
+ let excluded;
589
+ if (excludedJSON) {
590
+ try {
591
+ excluded = JSON.parse(excludedJSON);
592
+ if (!Array.isArray(excluded)) throw new Error("Excluded must be an array");
593
+ } catch (error) {
594
+ console.warn("[FluentPatternHandler] Invalid excluded parameter:", error);
595
+ }
596
+ }
597
+ let ids;
598
+ if (idsJSON) {
599
+ try {
600
+ ids = JSON.parse(idsJSON);
601
+ if (!Array.isArray(ids)) throw new Error("Ids must be an array");
602
+ } catch (error) {
603
+ console.warn("[FluentPatternHandler] Invalid ids parameter:", error);
604
+ }
605
+ }
606
+ return { filter, limit, offset, id, excluded, ids, filterFields };
389
607
  }
390
- is3xx() {
391
- return this.returnCode >= 300 && this.returnCode <= 399;
608
+ /**
609
+ * Applies filters to the query builder based on parsed parameters and options.
610
+ * @param queryBuilder - The QueryBuilder instance.
611
+ * @param params - Parsed query parameters.
612
+ * @param config - Query request configuration.
613
+ */
614
+ _applyParameters(queryBuilder, params) {
615
+ const { id, ids, filter, excluded } = params;
616
+ if (id) {
617
+ queryBuilder.match({ _id: new mongoose4.Types.ObjectId(id) });
618
+ } else if (ids && ids.length > 0) {
619
+ const objectIds = ids.map((id2) => new mongoose4.Types.ObjectId(id2));
620
+ queryBuilder.match({ _id: { $in: objectIds } });
621
+ } else {
622
+ const modelFilterFields = this._getFilterFieldsForModel(queryBuilder.getConfig().model);
623
+ if (filter && modelFilterFields.length > 0) {
624
+ const ors = modelFilterFields.map((field) => ({
625
+ [field]: { $regex: filter, $options: "i" }
626
+ }));
627
+ queryBuilder.match({ $or: ors });
628
+ }
629
+ if (params.filterFields && Object.keys(params.filterFields).length > 0) {
630
+ for (const [field, value] of Object.entries(params.filterFields)) {
631
+ if (!modelFilterFields.includes(field)) {
632
+ continue;
633
+ }
634
+ const match = {};
635
+ match[field] = { $regex: value, $options: "i" };
636
+ queryBuilder.match(match);
637
+ }
638
+ }
639
+ if (excluded && excluded.length > 0) {
640
+ const objectIds = excluded.map((id2) => new mongoose4.Types.ObjectId(id2));
641
+ queryBuilder.match({ _id: { $nin: objectIds } });
642
+ }
643
+ }
392
644
  }
393
- is4xx() {
394
- return this.returnCode >= 400 && this.returnCode <= 499;
645
+ /**
646
+ * Generates filter fields for the given Mongoose model based on schema options.
647
+ * @param model - The Mongoose model.
648
+ * @returns Array of filter fields.
649
+ */
650
+ _getFilterFieldsForModel(model) {
651
+ let filterFields = [];
652
+ let schema = model.schema;
653
+ schema.eachPath((path2, type) => {
654
+ if (type?.options?.filter == true) {
655
+ filterFields.push(path2);
656
+ }
657
+ });
658
+ return filterFields;
659
+ }
660
+ /**
661
+ * Builds execution parameters for the query builder.
662
+ * @param params - Parsed query parameters.
663
+ * @returns Execution parameters.
664
+ */
665
+ _buildExecutionConfig(params) {
666
+ const { id, limit, offset } = params;
667
+ return {
668
+ isOne: Boolean(id),
669
+ limit: limit === "full" ? void 0 : parseInt(limit || "5", 10),
670
+ skip: parseInt(offset || "0", 10)
671
+ };
672
+ }
673
+ /**
674
+ * Executes the query builder with applied filters and returns the result.
675
+ * @param params Execution parameters including the query builder and request query.
676
+ * @returns
677
+ */
678
+ async exec(params) {
679
+ try {
680
+ if (this._execMiddlewareFunctions && this._execMiddlewareFunctions.length > 0) {
681
+ for (const func of this._execMiddlewareFunctions) {
682
+ await func(params);
683
+ }
684
+ }
685
+ const queryParams = this._parseFluentRequestQuery(params.req.query);
686
+ this._applyParameters(params.queryBuilder, queryParams);
687
+ const execConfig = this._buildExecutionConfig(queryParams);
688
+ return await params.queryBuilder.exec(execConfig);
689
+ } catch (err) {
690
+ console.error("[ERROR - FluentPatternHandler]", err);
691
+ return new Codec({ data: [], meta: { total: 0 } }, 500);
692
+ }
395
693
  }
396
694
  };
695
+
696
+ // src/query-builder/query-builder.ts
697
+ import mongoose5 from "mongoose";
698
+
699
+ // src/query-builder/types.ts
397
700
  var JoinRelation = class {
398
701
  constructor(localField, ref, alias = void 0) {
399
702
  this.ref = ref;
@@ -402,7 +705,8 @@ var JoinRelation = class {
402
705
  }
403
706
  };
404
707
 
405
- // src/core/query-builder.ts
708
+ // src/query-builder/query-builder.ts
709
+ import { Codec as Codec2 } from "tsledge-core";
406
710
  var QueryBuilder = class {
407
711
  constructor(config) {
408
712
  this._matchConditions = {};
@@ -505,7 +809,7 @@ var QueryBuilder = class {
505
809
  if (schematype.options?.ref) {
506
810
  const refModelName = schematype.options.ref;
507
811
  try {
508
- const refModel = mongoose4.model(refModelName);
812
+ const refModel = mongoose5.model(refModelName);
509
813
  let alias = schematype.options?.alias ?? refModel.collection.name;
510
814
  this.join(new JoinRelation(fullPath, refModel, alias));
511
815
  } catch (err) {
@@ -514,10 +818,10 @@ var QueryBuilder = class {
514
818
  );
515
819
  }
516
820
  }
517
- if (schematype instanceof mongoose4.Schema.Types.Array && schematype.caster?.options?.ref) {
821
+ if (schematype instanceof mongoose5.Schema.Types.Array && schematype.caster?.options?.ref) {
518
822
  const refModelName = schematype.caster.options.ref;
519
823
  try {
520
- const refModel = mongoose4.model(refModelName);
824
+ const refModel = mongoose5.model(refModelName);
521
825
  let alias = schematype.caster.options?.alias ?? refModel.collection.name;
522
826
  this.join(new JoinRelation(fullPath, refModel, alias));
523
827
  } catch (err) {
@@ -599,10 +903,10 @@ var QueryBuilder = class {
599
903
  ]);
600
904
  const totalCount = countRes && countRes[0] ? countRes[0].n : 0;
601
905
  const documents = config && config.isOne ? await this._processSingleDocument(res) : await this._processMultipleDocuments(res);
602
- return new Codec({ data: documents, meta: { total: totalCount } }, 200);
906
+ return new Codec2({ data: documents, meta: { total: totalCount } }, 200);
603
907
  } catch (err) {
604
908
  console.error("[ERROR - QueryBuilder]", err);
605
- return new Codec({ data: [], meta: { total: 0 } }, 500);
909
+ return new Codec2({ data: [], meta: { total: 0 } }, 500);
606
910
  }
607
911
  }
608
912
  /**
@@ -643,175 +947,6 @@ var QueryBuilder = class {
643
947
  }
644
948
  };
645
949
 
646
- // src/fluent-interface/fluent-pattern-handler.ts
647
- var FluentPatternHandler = class _FluentPatternHandler {
648
- /**
649
- * Constructor for FluentPatternHandler.
650
- * @param execMiddleware - Optional array of middleware functions to be executed before the main query execution in the exec method.
651
- */
652
- constructor(execMiddleware = []) {
653
- /**
654
- * Array of middleware functions to be executed before the main query execution in the exec method. Each function receives the execution parameters and can modify them as needed.
655
- */
656
- this._execMiddlewareFunctions = [];
657
- if (_FluentPatternHandler._singleton) {
658
- throw new Error(
659
- "FluentPatternHandler is a singleton class. Use FluentPatternHandler.getInstance() to access the instance."
660
- );
661
- }
662
- this._execMiddlewareFunctions = execMiddleware;
663
- _FluentPatternHandler._singleton = this;
664
- }
665
- /**
666
- * Initializes the singleton instance of FluentPatternHandler with the provided options.
667
- * @param execMiddleware - Optional array of middleware functions to be executed before the main query execution in the exec method.
668
- * @returns Singleton instance of FluentPatternHandler.
669
- */
670
- static init(execMiddleware = []) {
671
- if (_FluentPatternHandler._singleton != void 0) {
672
- throw new Error("FluentPatternHandler is already initialized");
673
- }
674
- _FluentPatternHandler._singleton = new _FluentPatternHandler(execMiddleware);
675
- return _FluentPatternHandler._singleton;
676
- }
677
- /**
678
- * Returns the singleton instance of FluentPatternHandler.
679
- * @returns Singleton instance of FluentPatternHandler.
680
- */
681
- static getInstance() {
682
- if (_FluentPatternHandler._singleton == void 0) {
683
- throw new Error(
684
- "FluentPatternHandler instance has not been created yet. Please create an instance before calling getInstance()."
685
- );
686
- }
687
- return _FluentPatternHandler._singleton;
688
- }
689
- /**
690
- * Parses and validates query parameters from the request.
691
- * @param query - The query object from the request.
692
- * @returns Parsed query parameters.
693
- */
694
- _parseFluentRequestQuery(query) {
695
- const { filter, limit = "5", offset = "0", id, excluded: excludedJSON, ids: idsJSON } = query;
696
- const queryKeys = Object.keys(fluentRequestQueryAttributes);
697
- let filterFields = {};
698
- for (const [key, value] of Object.entries(query)) {
699
- if (queryKeys.includes(key)) continue;
700
- if (value == void 0) continue;
701
- try {
702
- filterFields[key] = typeof value === "string" ? value : JSON.stringify(value);
703
- } catch (e) {
704
- filterFields[key] = String(value);
705
- }
706
- }
707
- let excluded;
708
- if (excludedJSON) {
709
- try {
710
- excluded = JSON.parse(excludedJSON);
711
- if (!Array.isArray(excluded)) throw new Error("Excluded must be an array");
712
- } catch (error) {
713
- console.warn("[FluentPatternHandler] Invalid excluded parameter:", error);
714
- }
715
- }
716
- let ids;
717
- if (idsJSON) {
718
- try {
719
- ids = JSON.parse(idsJSON);
720
- if (!Array.isArray(ids)) throw new Error("Ids must be an array");
721
- } catch (error) {
722
- console.warn("[FluentPatternHandler] Invalid ids parameter:", error);
723
- }
724
- }
725
- return { filter, limit, offset, id, excluded, ids, filterFields };
726
- }
727
- /**
728
- * Applies filters to the query builder based on parsed parameters and options.
729
- * @param queryBuilder - The QueryBuilder instance.
730
- * @param params - Parsed query parameters.
731
- * @param config - Query request configuration.
732
- */
733
- _applyParameters(queryBuilder, params) {
734
- const { id, ids, filter, excluded } = params;
735
- if (id) {
736
- queryBuilder.match({ _id: new mongoose5.Types.ObjectId(id) });
737
- } else if (ids && ids.length > 0) {
738
- const objectIds = ids.map((id2) => new mongoose5.Types.ObjectId(id2));
739
- queryBuilder.match({ _id: { $in: objectIds } });
740
- } else {
741
- const modelFilterFields = this._getFilterFieldsForModel(queryBuilder.getConfig().model);
742
- if (filter && modelFilterFields.length > 0) {
743
- const ors = modelFilterFields.map((field) => ({
744
- [field]: { $regex: filter, $options: "i" }
745
- }));
746
- queryBuilder.match({ $or: ors });
747
- }
748
- if (params.filterFields && Object.keys(params.filterFields).length > 0) {
749
- for (const [field, value] of Object.entries(params.filterFields)) {
750
- if (!modelFilterFields.includes(field)) {
751
- continue;
752
- }
753
- const match = {};
754
- match[field] = { $regex: value, $options: "i" };
755
- queryBuilder.match(match);
756
- }
757
- }
758
- if (excluded && excluded.length > 0) {
759
- const objectIds = excluded.map((id2) => new mongoose5.Types.ObjectId(id2));
760
- queryBuilder.match({ _id: { $nin: objectIds } });
761
- }
762
- }
763
- }
764
- /**
765
- * Generates filter fields for the given Mongoose model based on schema options.
766
- * @param model - The Mongoose model.
767
- * @returns Array of filter fields.
768
- */
769
- _getFilterFieldsForModel(model) {
770
- let filterFields = [];
771
- let schema = model.schema;
772
- schema.eachPath((path2, type) => {
773
- if (type?.options?.filter == true) {
774
- filterFields.push(path2);
775
- }
776
- });
777
- return filterFields;
778
- }
779
- /**
780
- * Builds execution parameters for the query builder.
781
- * @param params - Parsed query parameters.
782
- * @returns Execution parameters.
783
- */
784
- _buildExecutionConfig(params) {
785
- const { id, limit, offset } = params;
786
- return {
787
- isOne: Boolean(id),
788
- limit: limit === "full" ? void 0 : parseInt(limit || "5", 10),
789
- skip: parseInt(offset || "0", 10)
790
- };
791
- }
792
- /**
793
- * Executes the query builder with applied filters and returns the result.
794
- * @param params Execution parameters including the query builder and request query.
795
- * @returns
796
- */
797
- async exec(params) {
798
- try {
799
- if (this._execMiddlewareFunctions && this._execMiddlewareFunctions.length > 0) {
800
- this._execMiddlewareFunctions.forEach((func) => {
801
- func(params);
802
- });
803
- }
804
- const queryParams = this._parseFluentRequestQuery(params.req.query);
805
- this._applyParameters(params.queryBuilder, queryParams);
806
- const execConfig = this._buildExecutionConfig(queryParams);
807
- return await params.queryBuilder.exec(execConfig);
808
- } catch (err) {
809
- console.error("[ERROR - FluentPatternHandler]", err);
810
- return new Codec({ data: [], meta: { total: 0 } }, 500);
811
- }
812
- }
813
- };
814
-
815
950
  // src/app.ts
816
951
  import express2 from "express";
817
952
  import cors from "cors";
@@ -1036,3 +1171,4 @@ setup();
1036
1171
  export {
1037
1172
  setup
1038
1173
  };
1174
+ //# sourceMappingURL=main.js.map