@kozojs/core 0.3.1 → 0.3.2

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/lib/index.js CHANGED
@@ -1,20 +1,3 @@
1
- import {
2
- BadRequestError,
3
- ConflictError,
4
- ForbiddenError,
5
- HttpError,
6
- InternalServerError,
7
- NotFoundError,
8
- UnauthorizedError,
9
- applyFileSystemRouting,
10
- clearRateLimitStore,
11
- cors,
12
- createFileSystemRouting,
13
- errorHandler,
14
- logger,
15
- rateLimit
16
- } from "./chunk-W44TTZNJ.js";
17
-
18
1
  // src/app.ts
19
2
  import { Hono } from "hono/quick";
20
3
  import { serve } from "@hono/node-server";
@@ -404,19 +387,19 @@ var ValidationFailedError = class extends KozoError {
404
387
  return new Response(JSON.stringify(body), INIT_400);
405
388
  }
406
389
  };
407
- var NotFoundError2 = class extends KozoError {
390
+ var NotFoundError = class extends KozoError {
408
391
  constructor(message = "Resource Not Found") {
409
392
  super(message, 404, "not-found");
410
393
  this.name = "NotFoundError";
411
394
  }
412
395
  };
413
- var UnauthorizedError2 = class extends KozoError {
396
+ var UnauthorizedError = class extends KozoError {
414
397
  constructor(message = "Unauthorized") {
415
398
  super(message, 401, "unauthorized");
416
399
  this.name = "UnauthorizedError";
417
400
  }
418
401
  };
419
- var ForbiddenError2 = class extends KozoError {
402
+ var ForbiddenError = class extends KozoError {
420
403
  constructor(message = "Forbidden") {
421
404
  super(message, 403, "forbidden");
422
405
  this.name = "ForbiddenError";
@@ -517,11 +500,11 @@ function uwsWrite404(uwsRes) {
517
500
  });
518
501
  }
519
502
  function getFreePort() {
520
- return new Promise((resolve, reject) => {
503
+ return new Promise((resolve2, reject) => {
521
504
  const srv = netCreateServer();
522
505
  srv.listen(0, "0.0.0.0", () => {
523
506
  const port = srv.address().port;
524
- srv.close((err) => err ? reject(err) : resolve(port));
507
+ srv.close((err) => err ? reject(err) : resolve2(port));
525
508
  });
526
509
  });
527
510
  }
@@ -538,7 +521,7 @@ async function createUwsServer(opts) {
538
521
  const { uws, routes } = opts;
539
522
  const port = opts.port === 0 ? await getFreePort() : opts.port;
540
523
  const emptyParams = Object.freeze({});
541
- return new Promise((resolve, reject) => {
524
+ return new Promise((resolve2, reject) => {
542
525
  const uwsApp = uws.App();
543
526
  for (const route of routes) {
544
527
  const fn = UWS_METHOD[route.method];
@@ -606,7 +589,7 @@ async function createUwsServer(opts) {
606
589
  return;
607
590
  }
608
591
  listenToken = token;
609
- resolve({
592
+ resolve2({
610
593
  port,
611
594
  server: {
612
595
  close() {
@@ -1875,8 +1858,8 @@ function createInflightTracker() {
1875
1858
  function trackRequest(tracker) {
1876
1859
  tracker.count++;
1877
1860
  let resolvePromise;
1878
- const promise = new Promise((resolve) => {
1879
- resolvePromise = resolve;
1861
+ const promise = new Promise((resolve2) => {
1862
+ resolvePromise = resolve2;
1880
1863
  });
1881
1864
  tracker.requests.add(promise);
1882
1865
  return () => {
@@ -1971,10 +1954,10 @@ var ShutdownManager = class {
1971
1954
  });
1972
1955
  }
1973
1956
  const drainPromise = this.drainRequests();
1974
- const timeoutPromise = new Promise((resolve) => {
1957
+ const timeoutPromise = new Promise((resolve2) => {
1975
1958
  setTimeout(() => {
1976
1959
  onShutdownTimeout?.(this.tracker.count);
1977
- resolve();
1960
+ resolve2();
1978
1961
  }, timeoutMs);
1979
1962
  });
1980
1963
  await Promise.race([drainPromise, timeoutPromise]);
@@ -2715,23 +2698,212 @@ function generateSwaggerHtml(specUrl, title = "API Documentation") {
2715
2698
  function createOpenAPIGenerator(config) {
2716
2699
  return new OpenAPIGenerator(config);
2717
2700
  }
2701
+
2702
+ // src/middleware/logger.ts
2703
+ function logger(options = {}) {
2704
+ const { prefix = "\u{1F310}", colorize = true } = options;
2705
+ return async (c, next) => {
2706
+ const start = Date.now();
2707
+ const method = c.req.method;
2708
+ const path = new URL(c.req.url).pathname;
2709
+ await next();
2710
+ const duration = Date.now() - start;
2711
+ const status = c.res.status;
2712
+ const statusColor = status >= 500 ? "\u{1F534}" : status >= 400 ? "\u{1F7E1}" : "\u{1F7E2}";
2713
+ const log = `${prefix} ${method.padEnd(6)} ${path} ${statusColor} ${status} ${duration}ms`;
2714
+ console.log(log);
2715
+ };
2716
+ }
2717
+
2718
+ // src/middleware/cors.ts
2719
+ import { cors as honoCors } from "hono/cors";
2720
+ function cors(options = {}) {
2721
+ return honoCors({
2722
+ origin: options.origin || "*",
2723
+ allowMethods: options.allowMethods || ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"],
2724
+ allowHeaders: options.allowHeaders || ["Content-Type", "Authorization"],
2725
+ exposeHeaders: options.exposeHeaders || [],
2726
+ maxAge: options.maxAge || 86400,
2727
+ credentials: options.credentials || false
2728
+ });
2729
+ }
2730
+
2731
+ // src/middleware/rate-limit.ts
2732
+ var store = /* @__PURE__ */ new Map();
2733
+ function rateLimit(options) {
2734
+ const {
2735
+ max = 100,
2736
+ window = 60,
2737
+ keyGenerator = (c) => c.req.header("x-forwarded-for") ?? c.req.header("x-real-ip") ?? "anonymous",
2738
+ message = "Too many requests"
2739
+ } = options;
2740
+ return async (c, next) => {
2741
+ const key = keyGenerator(c);
2742
+ const now = Date.now();
2743
+ const windowMs = window * 1e3;
2744
+ let record = store.get(key);
2745
+ if (!record || now > record.resetAt) {
2746
+ record = { count: 0, resetAt: now + windowMs };
2747
+ }
2748
+ record.count++;
2749
+ store.set(key, record);
2750
+ c.header("X-RateLimit-Limit", String(max));
2751
+ c.header("X-RateLimit-Remaining", String(Math.max(0, max - record.count)));
2752
+ c.header("X-RateLimit-Reset", String(Math.ceil(record.resetAt / 1e3)));
2753
+ if (record.count > max) {
2754
+ return c.json({ error: message }, 429);
2755
+ }
2756
+ await next();
2757
+ };
2758
+ }
2759
+ function clearRateLimitStore() {
2760
+ store.clear();
2761
+ }
2762
+
2763
+ // src/middleware/error-handler.ts
2764
+ var HttpError = class extends Error {
2765
+ constructor(statusCode, message, details) {
2766
+ super(message);
2767
+ this.statusCode = statusCode;
2768
+ this.details = details;
2769
+ this.name = "HttpError";
2770
+ }
2771
+ };
2772
+ var BadRequestError = class extends HttpError {
2773
+ constructor(message = "Bad Request", details) {
2774
+ super(400, message, details);
2775
+ }
2776
+ };
2777
+ var UnauthorizedError2 = class extends HttpError {
2778
+ constructor(message = "Unauthorized") {
2779
+ super(401, message);
2780
+ }
2781
+ };
2782
+ var ForbiddenError2 = class extends HttpError {
2783
+ constructor(message = "Forbidden") {
2784
+ super(403, message);
2785
+ }
2786
+ };
2787
+ var NotFoundError2 = class extends HttpError {
2788
+ constructor(message = "Not Found") {
2789
+ super(404, message);
2790
+ }
2791
+ };
2792
+ var ConflictError = class extends HttpError {
2793
+ constructor(message = "Conflict", details) {
2794
+ super(409, message, details);
2795
+ }
2796
+ };
2797
+ var InternalServerError = class extends HttpError {
2798
+ constructor(message = "Internal Server Error") {
2799
+ super(500, message);
2800
+ }
2801
+ };
2802
+ function errorHandler() {
2803
+ return async (c, next) => {
2804
+ try {
2805
+ await next();
2806
+ } catch (err) {
2807
+ if (err instanceof HttpError) {
2808
+ return c.json({
2809
+ error: err.message,
2810
+ status: err.statusCode,
2811
+ ...err.details ? { details: err.details } : {}
2812
+ }, err.statusCode);
2813
+ }
2814
+ console.error("Unhandled error:", err);
2815
+ return c.json({
2816
+ error: "Internal Server Error",
2817
+ status: 500
2818
+ }, 500);
2819
+ }
2820
+ };
2821
+ }
2822
+
2823
+ // src/middleware/fileSystemRouting.ts
2824
+ import { readFile } from "fs/promises";
2825
+ import { resolve } from "path";
2826
+ import { pathToFileURL as pathToFileURL2 } from "url";
2827
+ async function readManifest(manifestPath, onMissing) {
2828
+ try {
2829
+ const raw = await readFile(manifestPath, "utf-8");
2830
+ return JSON.parse(raw);
2831
+ } catch (err) {
2832
+ onMissing(err instanceof Error ? err : new Error(String(err)));
2833
+ return null;
2834
+ }
2835
+ }
2836
+ async function importHandler(handlerPath) {
2837
+ try {
2838
+ const url = handlerPath.startsWith("file://") ? handlerPath : pathToFileURL2(handlerPath).href;
2839
+ const mod = await import(url);
2840
+ if (typeof mod.default !== "function") {
2841
+ console.warn(
2842
+ `[kozo:fsr] Skipping ${handlerPath}: no default export function`
2843
+ );
2844
+ return null;
2845
+ }
2846
+ return mod.default;
2847
+ } catch (err) {
2848
+ console.warn(
2849
+ `[kozo:fsr] Failed to import handler ${handlerPath}:`,
2850
+ err.message
2851
+ );
2852
+ return null;
2853
+ }
2854
+ }
2855
+ async function applyFileSystemRouting(app, options = {}) {
2856
+ const {
2857
+ manifestPath = resolve(process.cwd(), "routes-manifest.json"),
2858
+ verbose = false,
2859
+ onMissingManifest = () => {
2860
+ },
2861
+ logger: logger2 = console.log
2862
+ } = options;
2863
+ const manifest = await readManifest(manifestPath, onMissingManifest);
2864
+ if (!manifest) return;
2865
+ const log = logger2;
2866
+ if (verbose) {
2867
+ log(
2868
+ `
2869
+ \u{1F4CB} [kozo:fsr] Loading ${manifest.routes.length} route(s) from manifest
2870
+ `
2871
+ );
2872
+ }
2873
+ for (const route of manifest.routes) {
2874
+ const handler = await importHandler(route.handler);
2875
+ if (!handler) continue;
2876
+ app[route.method](route.path, handler);
2877
+ if (verbose) {
2878
+ log(
2879
+ ` ${route.method.toUpperCase().padEnd(6)} ${route.path} \u2192 ${route.handler}`
2880
+ );
2881
+ }
2882
+ }
2883
+ if (verbose) {
2884
+ log("");
2885
+ }
2886
+ }
2887
+ function createFileSystemRouting(options = {}) {
2888
+ return (app) => applyFileSystemRouting(app, options);
2889
+ }
2718
2890
  export {
2719
2891
  ERROR_RESPONSES,
2720
- ForbiddenError2 as ForbiddenError,
2892
+ ForbiddenError,
2721
2893
  BadRequestError as HttpBadRequestError,
2722
2894
  ConflictError as HttpConflictError,
2723
2895
  HttpError,
2724
- ForbiddenError as HttpForbiddenError,
2896
+ ForbiddenError2 as HttpForbiddenError,
2725
2897
  InternalServerError as HttpInternalServerError,
2726
- NotFoundError as HttpNotFoundError,
2727
- UnauthorizedError as HttpUnauthorizedError,
2898
+ NotFoundError2 as HttpNotFoundError,
2899
+ UnauthorizedError2 as HttpUnauthorizedError,
2728
2900
  Kozo,
2729
2901
  KozoError,
2730
- NotFoundError2 as NotFoundError,
2902
+ NotFoundError,
2731
2903
  OpenAPIGenerator,
2732
2904
  SchemaCompiler,
2733
2905
  ShutdownManager,
2734
- UnauthorizedError2 as UnauthorizedError,
2906
+ UnauthorizedError,
2735
2907
  ValidationFailedError,
2736
2908
  applyFileSystemRouting,
2737
2909
  buildNativeContext,
@@ -2767,3 +2939,4 @@ export {
2767
2939
  validationErrorResponse,
2768
2940
  z
2769
2941
  };
2942
+ //# sourceMappingURL=index.js.map