canxjs 1.0.0 → 1.1.0

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/dist/index.js CHANGED
@@ -22777,14 +22777,14 @@ var require_messages = __commonJS((exports) => {
22777
22777
  length: 4
22778
22778
  };
22779
22779
 
22780
- class DatabaseError extends Error {
22780
+ class DatabaseError2 extends Error {
22781
22781
  constructor(message, length, name) {
22782
22782
  super(message);
22783
22783
  this.length = length;
22784
22784
  this.name = name;
22785
22785
  }
22786
22786
  }
22787
- exports.DatabaseError = DatabaseError;
22787
+ exports.DatabaseError = DatabaseError2;
22788
22788
 
22789
22789
  class CopyDataMessage {
22790
22790
  constructor(length, chunk) {
@@ -25326,7 +25326,7 @@ var require_lib5 = __commonJS((exports, module) => {
25326
25326
  var utils = require_utils();
25327
25327
  var Pool = require_pg_pool();
25328
25328
  var TypeOverrides = require_type_overrides();
25329
- var { DatabaseError } = require_dist();
25329
+ var { DatabaseError: DatabaseError2 } = require_dist();
25330
25330
  var { escapeIdentifier, escapeLiteral } = require_utils();
25331
25331
  var poolFactory = (Client2) => {
25332
25332
  return class BoundPool extends Pool {
@@ -25343,7 +25343,7 @@ var require_lib5 = __commonJS((exports, module) => {
25343
25343
  this._pools = [];
25344
25344
  this.Connection = Connection;
25345
25345
  this.types = require_pg_types();
25346
- this.DatabaseError = DatabaseError;
25346
+ this.DatabaseError = DatabaseError2;
25347
25347
  this.TypeOverrides = TypeOverrides;
25348
25348
  this.escapeIdentifier = escapeIdentifier;
25349
25349
  this.escapeLiteral = escapeLiteral;
@@ -25387,11 +25387,11 @@ __export(exports_esm, {
25387
25387
  Result: () => Result,
25388
25388
  Query: () => Query,
25389
25389
  Pool: () => Pool,
25390
- DatabaseError: () => DatabaseError,
25390
+ DatabaseError: () => DatabaseError2,
25391
25391
  Connection: () => Connection,
25392
25392
  Client: () => Client
25393
25393
  });
25394
- var import_lib, Client, Pool, Connection, types, Query, DatabaseError, escapeIdentifier, escapeLiteral, Result, TypeOverrides, defaults, esm_default;
25394
+ var import_lib, Client, Pool, Connection, types, Query, DatabaseError2, escapeIdentifier, escapeLiteral, Result, TypeOverrides, defaults, esm_default;
25395
25395
  var init_esm = __esm(() => {
25396
25396
  import_lib = __toESM(require_lib5(), 1);
25397
25397
  Client = import_lib.default.Client;
@@ -25399,7 +25399,7 @@ var init_esm = __esm(() => {
25399
25399
  Connection = import_lib.default.Connection;
25400
25400
  types = import_lib.default.types;
25401
25401
  Query = import_lib.default.Query;
25402
- DatabaseError = import_lib.default.DatabaseError;
25402
+ DatabaseError2 = import_lib.default.DatabaseError;
25403
25403
  escapeIdentifier = import_lib.default.escapeIdentifier;
25404
25404
  escapeLiteral = import_lib.default.escapeLiteral;
25405
25405
  Result = import_lib.default.Result;
@@ -26337,6 +26337,547 @@ var compress = () => {
26337
26337
  function createMiddlewarePipeline() {
26338
26338
  return new MiddlewarePipeline;
26339
26339
  }
26340
+ // src/middlewares/SecurityMiddleware.ts
26341
+ function security(config = {}) {
26342
+ return async (req, res, next) => {
26343
+ if (config.xssProtection !== false) {
26344
+ res.header("X-XSS-Protection", "1; mode=block");
26345
+ }
26346
+ if (config.contentTypeOptions !== false) {
26347
+ res.header("X-Content-Type-Options", "nosniff");
26348
+ }
26349
+ if (config.frameOptions) {
26350
+ res.header("X-Frame-Options", config.frameOptions);
26351
+ } else if (config.frameOptions !== undefined) {
26352
+ res.header("X-Frame-Options", config.frameOptions);
26353
+ } else {
26354
+ res.header("X-Frame-Options", "SAMEORIGIN");
26355
+ }
26356
+ if (config.hsts) {
26357
+ const maxAge = typeof config.hsts === "object" ? config.hsts.maxAge : 31536000;
26358
+ const includeSubDomains = typeof config.hsts === "object" && config.hsts.includeSubDomains ? "; includeSubDomains" : "";
26359
+ res.header("Strict-Transport-Security", `max-age=${maxAge}${includeSubDomains}`);
26360
+ }
26361
+ if (config.contentSecurityPolicy) {
26362
+ res.header("Content-Security-Policy", config.contentSecurityPolicy);
26363
+ }
26364
+ if (config.referrerPolicy) {
26365
+ res.header("Referrer-Policy", config.referrerPolicy);
26366
+ }
26367
+ return next();
26368
+ };
26369
+ }
26370
+ // src/middlewares/RateLimitMiddleware.ts
26371
+ class MemoryStore {
26372
+ hits = new Map;
26373
+ increment(key, windowMs) {
26374
+ const now = Date.now();
26375
+ let record = this.hits.get(key);
26376
+ if (!record || record.resetTime <= now) {
26377
+ record = { count: 1, resetTime: now + windowMs };
26378
+ } else {
26379
+ record.count++;
26380
+ }
26381
+ this.hits.set(key, record);
26382
+ return record;
26383
+ }
26384
+ }
26385
+ function rateLimit2(config) {
26386
+ const store = new MemoryStore;
26387
+ const {
26388
+ windowMs = 60000,
26389
+ max = 100,
26390
+ message = "Too many requests, please try again later.",
26391
+ statusCode = 429,
26392
+ keyGenerator = (req) => req.header("x-forwarded-for") || req.header("cf-connecting-ip") || "unknown-ip"
26393
+ } = config;
26394
+ return async (req, res, next) => {
26395
+ const key = keyGenerator(req);
26396
+ const { count, resetTime } = store.increment(key, windowMs);
26397
+ const remaining = Math.max(0, max - count);
26398
+ const resetDate = new Date(resetTime);
26399
+ res.header("X-RateLimit-Limit", String(max));
26400
+ res.header("X-RateLimit-Remaining", String(remaining));
26401
+ res.header("X-RateLimit-Reset", String(Math.ceil(resetTime / 1000)));
26402
+ if (count > max) {
26403
+ if (typeof message === "object") {
26404
+ return res.status(statusCode).json(message);
26405
+ }
26406
+ return res.status(statusCode).text(String(message));
26407
+ }
26408
+ return next();
26409
+ };
26410
+ }
26411
+ // src/utils/ErrorHandler.ts
26412
+ class CanxError extends Error {
26413
+ code;
26414
+ statusCode;
26415
+ details;
26416
+ timestamp;
26417
+ constructor(message, code = "CANX_ERROR", statusCode = 500, details) {
26418
+ super(message);
26419
+ this.name = "CanxError";
26420
+ this.code = code;
26421
+ this.statusCode = statusCode;
26422
+ this.details = details;
26423
+ this.timestamp = new Date;
26424
+ Error.captureStackTrace?.(this, this.constructor);
26425
+ }
26426
+ toJSON() {
26427
+ return {
26428
+ name: this.name,
26429
+ code: this.code,
26430
+ message: this.message,
26431
+ statusCode: this.statusCode,
26432
+ details: this.details,
26433
+ timestamp: this.timestamp.toISOString()
26434
+ };
26435
+ }
26436
+ }
26437
+
26438
+ class ValidationError extends CanxError {
26439
+ errors;
26440
+ constructor(errors, message = "Validation failed") {
26441
+ const errorMap = errors instanceof Map ? errors : new Map(Object.entries(errors));
26442
+ super(message, "VALIDATION_ERROR", 422, { errors: Object.fromEntries(errorMap) });
26443
+ this.name = "ValidationError";
26444
+ this.errors = errorMap;
26445
+ }
26446
+ }
26447
+
26448
+ class NotFoundError extends CanxError {
26449
+ constructor(resource = "Resource", id) {
26450
+ const message = id ? `${resource} with ID ${id} not found` : `${resource} not found`;
26451
+ super(message, "NOT_FOUND", 404, { resource, id });
26452
+ this.name = "NotFoundError";
26453
+ }
26454
+ }
26455
+
26456
+ class AuthenticationError extends CanxError {
26457
+ constructor(message = "Authentication required") {
26458
+ super(message, "AUTHENTICATION_ERROR", 401);
26459
+ this.name = "AuthenticationError";
26460
+ }
26461
+ }
26462
+
26463
+ class AuthorizationError extends CanxError {
26464
+ constructor(message = "You do not have permission to access this resource") {
26465
+ super(message, "AUTHORIZATION_ERROR", 403);
26466
+ this.name = "AuthorizationError";
26467
+ }
26468
+ }
26469
+
26470
+ class ConflictError extends CanxError {
26471
+ constructor(message = "Resource conflict", resource) {
26472
+ super(message, "CONFLICT_ERROR", 409, { resource });
26473
+ this.name = "ConflictError";
26474
+ }
26475
+ }
26476
+
26477
+ class RateLimitError extends CanxError {
26478
+ retryAfter;
26479
+ constructor(retryAfter = 60, message = "Too many requests") {
26480
+ super(message, "RATE_LIMIT_ERROR", 429, { retryAfter });
26481
+ this.name = "RateLimitError";
26482
+ this.retryAfter = retryAfter;
26483
+ }
26484
+ }
26485
+
26486
+ class BadRequestError extends CanxError {
26487
+ constructor(message = "Bad request") {
26488
+ super(message, "BAD_REQUEST", 400);
26489
+ this.name = "BadRequestError";
26490
+ }
26491
+ }
26492
+
26493
+ class DatabaseError extends CanxError {
26494
+ constructor(message = "Database error", originalError) {
26495
+ super(message, "DATABASE_ERROR", 500, {
26496
+ originalMessage: originalError?.message,
26497
+ stack: originalError?.stack
26498
+ });
26499
+ this.name = "DatabaseError";
26500
+ }
26501
+ }
26502
+
26503
+ class ServiceUnavailableError extends CanxError {
26504
+ constructor(service, message) {
26505
+ super(message || `Service ${service} is currently unavailable`, "SERVICE_UNAVAILABLE", 503, { service });
26506
+ this.name = "ServiceUnavailableError";
26507
+ }
26508
+ }
26509
+ function errorHandler(options = {}) {
26510
+ const { showStack = true, logErrors = true } = options;
26511
+ return async (req, res, next) => {
26512
+ try {
26513
+ return await next();
26514
+ } catch (error) {
26515
+ if (logErrors) {
26516
+ console.error(`[CanxJS Error] ${req.method} ${req.path}:`, error);
26517
+ }
26518
+ if (options.onError) {
26519
+ options.onError(error, req);
26520
+ }
26521
+ const isJson = req.header("accept")?.includes("application/json") ?? true;
26522
+ let statusCode = 500;
26523
+ let errorResponse = {
26524
+ code: "INTERNAL_ERROR",
26525
+ message: "Internal server error"
26526
+ };
26527
+ if (error instanceof CanxError) {
26528
+ statusCode = error.statusCode;
26529
+ errorResponse = {
26530
+ code: error.code,
26531
+ message: error.message,
26532
+ ...error.details && { details: error.details }
26533
+ };
26534
+ } else {
26535
+ const unknownError = error;
26536
+ errorResponse.message = showStack ? unknownError.message : "Internal server error";
26537
+ }
26538
+ if (showStack && error instanceof Error) {
26539
+ errorResponse.stack = error.stack;
26540
+ }
26541
+ if (isJson) {
26542
+ return res.status(statusCode).json({ error: errorResponse });
26543
+ } else {
26544
+ const html = `
26545
+ <!DOCTYPE html>
26546
+ <html>
26547
+ <head>
26548
+ <title>Error ${statusCode}</title>
26549
+ <style>
26550
+ body { font-family: system-ui, sans-serif; padding: 2rem; max-width: 800px; margin: 0 auto; }
26551
+ .error-box { background: #fee2e2; color: #991b1b; padding: 1.5rem; border-radius: 0.5rem; }
26552
+ pre { background: #f1f5f9; padding: 1rem; overflow-x: auto; border-radius: 0.5rem; }
26553
+ </style>
26554
+ </head>
26555
+ <body>
26556
+ <h1>Error ${statusCode}</h1>
26557
+ <div class="error-box">
26558
+ <p><strong>${errorResponse.code}</strong>: ${errorResponse.message}</p>
26559
+ </div>
26560
+ ${showStack && errorResponse.stack ? `<pre>${errorResponse.stack}</pre>` : ""}
26561
+ </body>
26562
+ </html>
26563
+ `;
26564
+ return res.status(statusCode).html(html);
26565
+ }
26566
+ }
26567
+ };
26568
+ }
26569
+ function asyncHandler(fn) {
26570
+ return async (req, res) => {
26571
+ try {
26572
+ return await fn(req, res);
26573
+ } catch (error) {
26574
+ if (error instanceof CanxError) {
26575
+ return res.status(error.statusCode).json(error.toJSON());
26576
+ }
26577
+ throw error;
26578
+ }
26579
+ };
26580
+ }
26581
+ function assertFound(value, resource = "Resource", id) {
26582
+ if (value === null || value === undefined) {
26583
+ throw new NotFoundError(resource, id);
26584
+ }
26585
+ return value;
26586
+ }
26587
+ function assertAuthenticated(user) {
26588
+ if (!user) {
26589
+ throw new AuthenticationError;
26590
+ }
26591
+ return user;
26592
+ }
26593
+ function assertAuthorized(condition, message) {
26594
+ if (!condition) {
26595
+ throw new AuthorizationError(message);
26596
+ }
26597
+ }
26598
+ function assertValid(valid, errors) {
26599
+ if (!valid) {
26600
+ throw new ValidationError(errors || new Map);
26601
+ }
26602
+ }
26603
+ var errors = {
26604
+ CanxError,
26605
+ ValidationError,
26606
+ NotFoundError,
26607
+ AuthenticationError,
26608
+ AuthorizationError,
26609
+ ConflictError,
26610
+ RateLimitError,
26611
+ BadRequestError,
26612
+ DatabaseError,
26613
+ ServiceUnavailableError
26614
+ };
26615
+ var ErrorHandler_default = {
26616
+ ...errors,
26617
+ errorHandler,
26618
+ asyncHandler,
26619
+ assertFound,
26620
+ assertAuthenticated,
26621
+ assertAuthorized,
26622
+ assertValid
26623
+ };
26624
+
26625
+ // src/middlewares/ValidationMiddleware.ts
26626
+ function validateSchema(schema, target = "body") {
26627
+ return async (req, res, next) => {
26628
+ let data;
26629
+ if (target === "body") {
26630
+ data = await req.body();
26631
+ } else if (target === "query") {
26632
+ data = req.query;
26633
+ } else {
26634
+ data = req.params;
26635
+ }
26636
+ try {
26637
+ const validated = schema.parse(data);
26638
+ req.validatedData = validated;
26639
+ return next();
26640
+ } catch (error) {
26641
+ if (error instanceof ValidationError) {
26642
+ return res.status(422).json({
26643
+ error: {
26644
+ code: "VALIDATION_ERROR",
26645
+ message: "Validation failed",
26646
+ details: Object.fromEntries(error.errors)
26647
+ }
26648
+ });
26649
+ }
26650
+ throw error;
26651
+ }
26652
+ };
26653
+ }
26654
+ // src/schema/Schema.ts
26655
+ class Schema {
26656
+ _output;
26657
+ _input;
26658
+ description;
26659
+ isOptional = false;
26660
+ safeParse(value) {
26661
+ try {
26662
+ const data = this.parse(value);
26663
+ return { success: true, data };
26664
+ } catch (error) {
26665
+ if (error instanceof ValidationError) {
26666
+ return { success: false, error };
26667
+ }
26668
+ throw error;
26669
+ }
26670
+ }
26671
+ optional() {
26672
+ const newSchema = Object.create(this);
26673
+ newSchema.isOptional = true;
26674
+ return newSchema;
26675
+ }
26676
+ describe(description) {
26677
+ this.description = description;
26678
+ return this;
26679
+ }
26680
+ }
26681
+
26682
+ class StringSchema extends Schema {
26683
+ checks = [];
26684
+ constructor() {
26685
+ super();
26686
+ }
26687
+ min(length, message) {
26688
+ this.checks.push((v) => v.length >= length ? null : message || `String must contain at least ${length} character(s)`);
26689
+ return this;
26690
+ }
26691
+ max(length, message) {
26692
+ this.checks.push((v) => v.length <= length ? null : message || `String must contain at most ${length} character(s)`);
26693
+ return this;
26694
+ }
26695
+ email(message) {
26696
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
26697
+ this.checks.push((v) => emailRegex.test(v) ? null : message || "Invalid email address");
26698
+ return this;
26699
+ }
26700
+ parse(value) {
26701
+ if (this.isOptional && (value === undefined || value === null)) {
26702
+ return value;
26703
+ }
26704
+ if (typeof value !== "string") {
26705
+ throw new ValidationError({ _errors: ["Expected string, received " + typeof value] });
26706
+ }
26707
+ for (const check of this.checks) {
26708
+ const error = check(value);
26709
+ if (error) {
26710
+ throw new ValidationError({ _errors: [error] });
26711
+ }
26712
+ }
26713
+ return value;
26714
+ }
26715
+ getJsonSchema() {
26716
+ return {
26717
+ type: "string",
26718
+ description: this.description
26719
+ };
26720
+ }
26721
+ }
26722
+
26723
+ class NumberSchema extends Schema {
26724
+ checks = [];
26725
+ min(min, message) {
26726
+ this.checks.push((v) => v >= min ? null : message || `Number must be greater than or equal to ${min}`);
26727
+ return this;
26728
+ }
26729
+ max(max, message) {
26730
+ this.checks.push((v) => v <= max ? null : message || `Number must be less than or equal to ${max}`);
26731
+ return this;
26732
+ }
26733
+ parse(value) {
26734
+ if (this.isOptional && (value === undefined || value === null)) {
26735
+ return value;
26736
+ }
26737
+ if (typeof value !== "number" || isNaN(value)) {
26738
+ if (typeof value === "string" && !isNaN(parseFloat(value))) {
26739
+ const num = parseFloat(value);
26740
+ return this.validateChecks(num);
26741
+ }
26742
+ throw new ValidationError({ _errors: ["Expected number, received " + typeof value] });
26743
+ }
26744
+ return this.validateChecks(value);
26745
+ }
26746
+ validateChecks(value) {
26747
+ for (const check of this.checks) {
26748
+ const error = check(value);
26749
+ if (error) {
26750
+ throw new ValidationError({ _errors: [error] });
26751
+ }
26752
+ }
26753
+ return value;
26754
+ }
26755
+ getJsonSchema() {
26756
+ return {
26757
+ type: "number",
26758
+ description: this.description
26759
+ };
26760
+ }
26761
+ }
26762
+
26763
+ class BooleanSchema extends Schema {
26764
+ parse(value) {
26765
+ if (this.isOptional && (value === undefined || value === null)) {
26766
+ return value;
26767
+ }
26768
+ if (typeof value === "boolean")
26769
+ return value;
26770
+ if (value === "true")
26771
+ return true;
26772
+ if (value === "false")
26773
+ return false;
26774
+ throw new ValidationError({ _errors: ["Expected boolean, received " + typeof value] });
26775
+ }
26776
+ getJsonSchema() {
26777
+ return {
26778
+ type: "boolean",
26779
+ description: this.description
26780
+ };
26781
+ }
26782
+ }
26783
+
26784
+ class ObjectSchema extends Schema {
26785
+ shape;
26786
+ constructor(shape) {
26787
+ super();
26788
+ this.shape = shape;
26789
+ }
26790
+ parse(value) {
26791
+ if (this.isOptional && (value === undefined || value === null)) {
26792
+ return value;
26793
+ }
26794
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
26795
+ throw new ValidationError({ _errors: ["Expected object, received " + typeof value] });
26796
+ }
26797
+ const result = {};
26798
+ const errors2 = new Map;
26799
+ for (const [key, schema] of Object.entries(this.shape)) {
26800
+ try {
26801
+ result[key] = schema.parse(value[key]);
26802
+ } catch (error) {
26803
+ if (error instanceof ValidationError) {
26804
+ const fieldErrors = error.errors.get("_errors") || [];
26805
+ if (error.errors.size > 0 && !error.errors.has("_errors")) {
26806
+ error.errors.forEach((msgs, path) => {
26807
+ errors2.set(`${key}.${path}`, msgs);
26808
+ });
26809
+ } else {
26810
+ errors2.set(key, fieldErrors);
26811
+ }
26812
+ } else {
26813
+ errors2.set(key, ["Invalid value"]);
26814
+ }
26815
+ }
26816
+ }
26817
+ if (errors2.size > 0) {
26818
+ throw new ValidationError(errors2);
26819
+ }
26820
+ return result;
26821
+ }
26822
+ getJsonSchema() {
26823
+ const properties = {};
26824
+ const required = [];
26825
+ for (const [key, schema] of Object.entries(this.shape)) {
26826
+ properties[key] = schema.getJsonSchema();
26827
+ if (!schema.isOptional) {
26828
+ if (!schema.isOptional) {
26829
+ required.push(key);
26830
+ }
26831
+ }
26832
+ }
26833
+ return {
26834
+ type: "object",
26835
+ properties,
26836
+ required: required.length > 0 ? required : undefined,
26837
+ description: this.description
26838
+ };
26839
+ }
26840
+ }
26841
+
26842
+ class ArraySchema extends Schema {
26843
+ element;
26844
+ constructor(element) {
26845
+ super();
26846
+ this.element = element;
26847
+ }
26848
+ parse(value) {
26849
+ if (this.isOptional && (value === undefined || value === null)) {
26850
+ return value;
26851
+ }
26852
+ if (!Array.isArray(value)) {
26853
+ throw new ValidationError({ _errors: ["Expected array, received " + typeof value] });
26854
+ }
26855
+ return value.map((item, index) => {
26856
+ try {
26857
+ return this.element.parse(item);
26858
+ } catch (error) {
26859
+ if (error instanceof ValidationError) {
26860
+ throw new ValidationError({ [index]: error.errors.get("_errors") || ["Invalid Item"] });
26861
+ }
26862
+ throw error;
26863
+ }
26864
+ });
26865
+ }
26866
+ getJsonSchema() {
26867
+ return {
26868
+ type: "array",
26869
+ items: this.element.getJsonSchema(),
26870
+ description: this.description
26871
+ };
26872
+ }
26873
+ }
26874
+ var z = {
26875
+ string: () => new StringSchema,
26876
+ number: () => new NumberSchema,
26877
+ boolean: () => new BooleanSchema,
26878
+ object: (shape) => new ObjectSchema(shape),
26879
+ array: (element) => new ArraySchema(element)
26880
+ };
26340
26881
  // src/mvc/Controller.ts
26341
26882
  var controllerMeta = new WeakMap;
26342
26883
  function getControllerMeta(target) {
@@ -27600,7 +28141,7 @@ class TableBuilder {
27600
28141
  ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4`;
27601
28142
  }
27602
28143
  }
27603
- var Schema = {
28144
+ var Schema2 = {
27604
28145
  async create(table, callback) {
27605
28146
  const builder = new TableBuilder(table);
27606
28147
  callback(builder);
@@ -27631,9 +28172,9 @@ var Schema = {
27631
28172
  class Migrator {
27632
28173
  migrations = [];
27633
28174
  async ensureTable() {
27634
- const exists = await Schema.hasTable("migrations");
28175
+ const exists = await Schema2.hasTable("migrations");
27635
28176
  if (!exists) {
27636
- await Schema.create("migrations", (table) => {
28177
+ await Schema2.create("migrations", (table) => {
27637
28178
  table.id();
27638
28179
  table.string("name").unique();
27639
28180
  table.integer("batch");
@@ -29494,7 +30035,7 @@ function parseRule(rule) {
29494
30035
  return { name, param };
29495
30036
  }
29496
30037
  function validate(data, schema) {
29497
- const errors = new Map;
30038
+ const errors2 = new Map;
29498
30039
  const validData = {};
29499
30040
  for (const [field, rules] of Object.entries(schema)) {
29500
30041
  const value = data[field];
@@ -29530,12 +30071,12 @@ function validate(data, schema) {
29530
30071
  }
29531
30072
  }
29532
30073
  if (fieldErrors.length > 0) {
29533
- errors.set(field, fieldErrors);
30074
+ errors2.set(field, fieldErrors);
29534
30075
  } else if (value !== undefined) {
29535
30076
  validData[field] = value;
29536
30077
  }
29537
30078
  }
29538
- return { valid: errors.size === 0, errors, data: validData };
30079
+ return { valid: errors2.size === 0, errors: errors2, data: validData };
29539
30080
  }
29540
30081
  function validateAsync(data, schema) {
29541
30082
  return Promise.resolve(validate(data, schema));
@@ -29764,193 +30305,6 @@ class RequestParser {
29764
30305
  function parseRequest(raw) {
29765
30306
  return new RequestParser(raw);
29766
30307
  }
29767
- // src/utils/ErrorHandler.ts
29768
- class CanxError extends Error {
29769
- code;
29770
- statusCode;
29771
- details;
29772
- timestamp;
29773
- constructor(message, code = "CANX_ERROR", statusCode = 500, details) {
29774
- super(message);
29775
- this.name = "CanxError";
29776
- this.code = code;
29777
- this.statusCode = statusCode;
29778
- this.details = details;
29779
- this.timestamp = new Date;
29780
- Error.captureStackTrace?.(this, this.constructor);
29781
- }
29782
- toJSON() {
29783
- return {
29784
- name: this.name,
29785
- code: this.code,
29786
- message: this.message,
29787
- statusCode: this.statusCode,
29788
- details: this.details,
29789
- timestamp: this.timestamp.toISOString()
29790
- };
29791
- }
29792
- }
29793
-
29794
- class ValidationError extends CanxError {
29795
- errors;
29796
- constructor(errors, message = "Validation failed") {
29797
- const errorMap = errors instanceof Map ? errors : new Map(Object.entries(errors));
29798
- super(message, "VALIDATION_ERROR", 422, { errors: Object.fromEntries(errorMap) });
29799
- this.name = "ValidationError";
29800
- this.errors = errorMap;
29801
- }
29802
- }
29803
-
29804
- class NotFoundError extends CanxError {
29805
- constructor(resource = "Resource", id) {
29806
- const message = id ? `${resource} with ID ${id} not found` : `${resource} not found`;
29807
- super(message, "NOT_FOUND", 404, { resource, id });
29808
- this.name = "NotFoundError";
29809
- }
29810
- }
29811
-
29812
- class AuthenticationError extends CanxError {
29813
- constructor(message = "Authentication required") {
29814
- super(message, "AUTHENTICATION_ERROR", 401);
29815
- this.name = "AuthenticationError";
29816
- }
29817
- }
29818
-
29819
- class AuthorizationError extends CanxError {
29820
- constructor(message = "You do not have permission to access this resource") {
29821
- super(message, "AUTHORIZATION_ERROR", 403);
29822
- this.name = "AuthorizationError";
29823
- }
29824
- }
29825
-
29826
- class ConflictError extends CanxError {
29827
- constructor(message = "Resource conflict", resource) {
29828
- super(message, "CONFLICT_ERROR", 409, { resource });
29829
- this.name = "ConflictError";
29830
- }
29831
- }
29832
-
29833
- class RateLimitError extends CanxError {
29834
- retryAfter;
29835
- constructor(retryAfter = 60, message = "Too many requests") {
29836
- super(message, "RATE_LIMIT_ERROR", 429, { retryAfter });
29837
- this.name = "RateLimitError";
29838
- this.retryAfter = retryAfter;
29839
- }
29840
- }
29841
-
29842
- class BadRequestError extends CanxError {
29843
- constructor(message = "Bad request") {
29844
- super(message, "BAD_REQUEST", 400);
29845
- this.name = "BadRequestError";
29846
- }
29847
- }
29848
-
29849
- class DatabaseError2 extends CanxError {
29850
- constructor(message = "Database error", originalError) {
29851
- super(message, "DATABASE_ERROR", 500, {
29852
- originalMessage: originalError?.message,
29853
- stack: originalError?.stack
29854
- });
29855
- this.name = "DatabaseError";
29856
- }
29857
- }
29858
-
29859
- class ServiceUnavailableError extends CanxError {
29860
- constructor(service, message) {
29861
- super(message || `Service ${service} is currently unavailable`, "SERVICE_UNAVAILABLE", 503, { service });
29862
- this.name = "ServiceUnavailableError";
29863
- }
29864
- }
29865
- function errorHandler(options = {}) {
29866
- const { showStack = true, logErrors = true } = options;
29867
- return async (req, res, next) => {
29868
- try {
29869
- return await next();
29870
- } catch (error) {
29871
- if (logErrors) {
29872
- console.error(`[CanxJS Error] ${req.method} ${req.path}:`, error);
29873
- }
29874
- if (options.onError) {
29875
- options.onError(error, req);
29876
- }
29877
- if (error instanceof CanxError) {
29878
- const response2 = {
29879
- error: {
29880
- code: error.code,
29881
- message: error.message,
29882
- ...error.details && { details: error.details },
29883
- ...showStack && { stack: error.stack }
29884
- }
29885
- };
29886
- return res.status(error.statusCode).json(response2);
29887
- }
29888
- const unknownError = error;
29889
- return res.status(500).json({
29890
- error: {
29891
- code: "INTERNAL_ERROR",
29892
- message: showStack ? unknownError.message : "Internal server error",
29893
- ...showStack && { stack: unknownError.stack }
29894
- }
29895
- });
29896
- }
29897
- };
29898
- }
29899
- function asyncHandler(fn) {
29900
- return async (req, res) => {
29901
- try {
29902
- return await fn(req, res);
29903
- } catch (error) {
29904
- if (error instanceof CanxError) {
29905
- return res.status(error.statusCode).json(error.toJSON());
29906
- }
29907
- throw error;
29908
- }
29909
- };
29910
- }
29911
- function assertFound(value, resource = "Resource", id) {
29912
- if (value === null || value === undefined) {
29913
- throw new NotFoundError(resource, id);
29914
- }
29915
- return value;
29916
- }
29917
- function assertAuthenticated(user) {
29918
- if (!user) {
29919
- throw new AuthenticationError;
29920
- }
29921
- return user;
29922
- }
29923
- function assertAuthorized(condition, message) {
29924
- if (!condition) {
29925
- throw new AuthorizationError(message);
29926
- }
29927
- }
29928
- function assertValid(valid, errors) {
29929
- if (!valid) {
29930
- throw new ValidationError(errors || new Map);
29931
- }
29932
- }
29933
- var errors = {
29934
- CanxError,
29935
- ValidationError,
29936
- NotFoundError,
29937
- AuthenticationError,
29938
- AuthorizationError,
29939
- ConflictError,
29940
- RateLimitError,
29941
- BadRequestError,
29942
- DatabaseError: DatabaseError2,
29943
- ServiceUnavailableError
29944
- };
29945
- var ErrorHandler_default = {
29946
- ...errors,
29947
- errorHandler,
29948
- asyncHandler,
29949
- assertFound,
29950
- assertAuthenticated,
29951
- assertAuthorized,
29952
- assertValid
29953
- };
29954
30308
  // src/utils/Logger.ts
29955
30309
  var LOG_LEVELS = {
29956
30310
  debug: 0,
@@ -30870,8 +31224,13 @@ class Canx {
30870
31224
  return this;
30871
31225
  }
30872
31226
  async listen(port, callback) {
30873
- if (port)
31227
+ if (typeof port === "function") {
31228
+ callback = port;
31229
+ port = undefined;
31230
+ }
31231
+ if (port && typeof port === "number") {
30874
31232
  this.config.port = port;
31233
+ }
30875
31234
  for (const plugin of this.plugins) {
30876
31235
  await plugin.install(this);
30877
31236
  }
@@ -30919,9 +31278,11 @@ function createApp(config) {
30919
31278
  return new Canx(config);
30920
31279
  }
30921
31280
  export {
31281
+ z,
30922
31282
  ws,
30923
31283
  verifyPassword,
30924
31284
  verifyJWT,
31285
+ validateSchema,
30925
31286
  validateAsync,
30926
31287
  validate,
30927
31288
  useI18n,
@@ -30935,6 +31296,7 @@ export {
30935
31296
  sendMail,
30936
31297
  factory as seederFactory,
30937
31298
  seeder,
31299
+ security,
30938
31300
  roles,
30939
31301
  response,
30940
31302
  resolve,
@@ -30942,6 +31304,7 @@ export {
30942
31304
  renderPage,
30943
31305
  render,
30944
31306
  redisCheck,
31307
+ rateLimit2 as rateLimitMiddleware,
30945
31308
  rateLimit,
30946
31309
  randomUuid,
30947
31310
  randomString,
@@ -31031,13 +31394,14 @@ export {
31031
31394
  assertFound,
31032
31395
  assertAuthorized,
31033
31396
  assertAuthenticated,
31397
+ Schema as ZSchema,
31034
31398
  WebSocketServer,
31035
31399
  ValidationError,
31036
31400
  TestClient,
31037
31401
  ServiceUnavailableError,
31038
31402
  Server,
31039
31403
  ScopedContainer,
31040
- Schema,
31404
+ Schema2 as Schema,
31041
31405
  S3Driver,
31042
31406
  Router,
31043
31407
  ResponseBuilder,
@@ -31068,7 +31432,7 @@ export {
31068
31432
  EventServiceProvider,
31069
31433
  EventEmitter,
31070
31434
  Delete,
31071
- DatabaseError2 as DatabaseError,
31435
+ DatabaseError,
31072
31436
  Controller,
31073
31437
  Container,
31074
31438
  ConflictError,