shokupan 0.4.4 → 0.5.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.
Files changed (44) hide show
  1. package/README.md +7 -8
  2. package/dist/analysis/openapi-analyzer.d.ts +0 -4
  3. package/dist/cli.cjs +1 -1
  4. package/dist/cli.js +1 -1
  5. package/dist/context.d.ts +3 -3
  6. package/dist/index.cjs +38 -39
  7. package/dist/index.cjs.map +1 -1
  8. package/dist/index.js +38 -39
  9. package/dist/index.js.map +1 -1
  10. package/dist/{openapi-analyzer-BtIaHIfe.js → openapi-analyzer-D7y6Qa38.js} +31 -34
  11. package/dist/openapi-analyzer-D7y6Qa38.js.map +1 -0
  12. package/dist/{openapi-analyzer-D9YB3IkV.cjs → openapi-analyzer-z-7AoFRC.cjs} +31 -34
  13. package/dist/openapi-analyzer-z-7AoFRC.cjs.map +1 -0
  14. package/dist/plugins/scalar.d.ts +2 -2
  15. package/dist/server-adapter-BWrEJbKL.js.map +1 -1
  16. package/dist/server-adapter-fVKP60e0.cjs.map +1 -1
  17. package/dist/shokupan.d.ts +6 -5
  18. package/dist/types.d.ts +2 -1
  19. package/package.json +1 -1
  20. package/dist/benchmarking/advanced-cases/elysia.d.ts +0 -1
  21. package/dist/benchmarking/advanced-cases/express.d.ts +0 -1
  22. package/dist/benchmarking/advanced-cases/fastify.d.ts +0 -1
  23. package/dist/benchmarking/advanced-cases/hapi.d.ts +0 -1
  24. package/dist/benchmarking/advanced-cases/hono.d.ts +0 -1
  25. package/dist/benchmarking/advanced-cases/koa.d.ts +0 -1
  26. package/dist/benchmarking/advanced-cases/nest.d.ts +0 -1
  27. package/dist/benchmarking/advanced-cases/shokupan.d.ts +0 -1
  28. package/dist/benchmarking/advanced-data.d.ts +0 -33
  29. package/dist/benchmarking/advanced-runner.d.ts +0 -1
  30. package/dist/benchmarking/advanced-worker.d.ts +0 -0
  31. package/dist/benchmarking/cases/elysia.d.ts +0 -1
  32. package/dist/benchmarking/cases/express.d.ts +0 -1
  33. package/dist/benchmarking/cases/fastify.d.ts +0 -1
  34. package/dist/benchmarking/cases/hapi.d.ts +0 -1
  35. package/dist/benchmarking/cases/hono.d.ts +0 -1
  36. package/dist/benchmarking/cases/koa.d.ts +0 -1
  37. package/dist/benchmarking/cases/nest.d.ts +0 -1
  38. package/dist/benchmarking/cases/shokupan.d.ts +0 -1
  39. package/dist/benchmarking/data.d.ts +0 -15
  40. package/dist/benchmarking/quick_bench.d.ts +0 -1
  41. package/dist/benchmarking/runner.d.ts +0 -1
  42. package/dist/benchmarking/worker.d.ts +0 -0
  43. package/dist/openapi-analyzer-BtIaHIfe.js.map +0 -1
  44. package/dist/openapi-analyzer-D9YB3IkV.cjs.map +0 -1
package/README.md CHANGED
@@ -31,16 +31,15 @@ Shokupan is designed to make building APIs delightful again. With zero-config de
31
31
  > Bun and TypeScript are recommended for Shokupan, though it also supports Node.js and standard JavaScript.
32
32
 
33
33
  ```typescript
34
- import { Shokupan } from 'shokupan';
34
+ import { Shokupan, ScalarPlugin } from 'shokupan';
35
+ const app = new Shokupan();
35
36
 
36
- const app = new Shokupan({
37
- port: 3000,
38
- development: true
39
- });
37
+ app.get('/', (ctx) => ({ message: 'Hello, World!' }));
38
+ app.get('/hello', (ctx) => "world");
40
39
 
41
- app.get('/', (ctx) => {
42
- return { message: 'Hello, World!' };
43
- });
40
+ app.mount('/scalar', new ScalarPlugin({
41
+ enableStaticAnalysis: true
42
+ }));
44
43
 
45
44
  app.listen();
46
45
  ```
@@ -130,10 +130,6 @@ export declare class OpenAPIAnalyzer {
130
130
  * Generate OpenAPI specification
131
131
  */
132
132
  generateOpenAPISpec(): any;
133
- /**
134
- * Convert a type string to an OpenAPI schema
135
- */
136
- private typeToSchema;
137
133
  }
138
134
  /**
139
135
  * Analyze a directory and generate OpenAPI spec
package/dist/cli.cjs CHANGED
@@ -4,7 +4,7 @@ const p = require("@clack/prompts");
4
4
  const fs = require("node:fs");
5
5
  const path = require("node:path");
6
6
  const promises = require("node:timers/promises");
7
- const openapiAnalyzer = require("./openapi-analyzer-D9YB3IkV.cjs");
7
+ const openapiAnalyzer = require("./openapi-analyzer-z-7AoFRC.cjs");
8
8
  function _interopNamespaceDefault(e) {
9
9
  const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
10
10
  if (e) {
package/dist/cli.js CHANGED
@@ -3,7 +3,7 @@ import * as p from "@clack/prompts";
3
3
  import fs from "node:fs";
4
4
  import path from "node:path";
5
5
  import { setTimeout } from "node:timers/promises";
6
- import { analyzeDirectory } from "./openapi-analyzer-BtIaHIfe.js";
6
+ import { analyzeDirectory } from "./openapi-analyzer-D7y6Qa38.js";
7
7
  const templates = {
8
8
  controller: (name) => `import { Controller, Get, Ctx } from 'shokupan';
9
9
  import { ShokupanContext } from 'shokupan';
package/dist/context.d.ts CHANGED
@@ -20,7 +20,7 @@ export interface DebugCollector {
20
20
  }
21
21
  export declare class ShokupanContext<State extends Record<string, any> = Record<string, any>> {
22
22
  readonly request: ShokupanRequest<any>;
23
- readonly server?: Server<any>;
23
+ readonly server?: Server;
24
24
  readonly app?: Shokupan;
25
25
  readonly signal?: AbortSignal;
26
26
  private _url;
@@ -31,7 +31,7 @@ export declare class ShokupanContext<State extends Record<string, any> = Record<
31
31
  _debug?: DebugCollector;
32
32
  _finalResponse?: Response;
33
33
  _rawBody?: string | ArrayBuffer | Uint8Array;
34
- constructor(request: ShokupanRequest<any>, server?: Server<any>, state?: State, app?: Shokupan, signal?: AbortSignal, // Optional as it might not be provided in tests or simple creates
34
+ constructor(request: ShokupanRequest<any>, server?: Server, state?: State, app?: Shokupan, signal?: AbortSignal, // Optional as it might not be provided in tests or simple creates
35
35
  enableMiddlewareTracking?: boolean);
36
36
  get url(): URL;
37
37
  /**
@@ -53,7 +53,7 @@ export declare class ShokupanContext<State extends Record<string, any> = Record<
53
53
  /**
54
54
  * Client IP address
55
55
  */
56
- get ip(): any;
56
+ get ip(): Bun.SocketAddress;
57
57
  /**
58
58
  * Request hostname (e.g. "localhost")
59
59
  */
package/dist/index.cjs CHANGED
@@ -16,7 +16,7 @@ const Ajv = require("ajv");
16
16
  const addFormats = require("ajv-formats");
17
17
  const classTransformer = require("class-transformer");
18
18
  const classValidator = require("class-validator");
19
- const openapiAnalyzer = require("./openapi-analyzer-D9YB3IkV.cjs");
19
+ const openapiAnalyzer = require("./openapi-analyzer-z-7AoFRC.cjs");
20
20
  const crypto = require("crypto");
21
21
  const events = require("events");
22
22
  function _interopNamespaceDefault(e) {
@@ -879,7 +879,7 @@ async function generateOpenApi(rootRouter, options = {}) {
879
879
  const defaultTagName = options.defaultTag || "Application";
880
880
  let astRoutes = [];
881
881
  try {
882
- const { OpenAPIAnalyzer } = await Promise.resolve().then(() => require("./openapi-analyzer-D9YB3IkV.cjs"));
882
+ const { OpenAPIAnalyzer } = await Promise.resolve().then(() => require("./openapi-analyzer-z-7AoFRC.cjs"));
883
883
  const analyzer = new OpenAPIAnalyzer(process.cwd());
884
884
  const { applications } = await analyzer.analyze();
885
885
  const appMap = /* @__PURE__ */ new Map();
@@ -2092,34 +2092,36 @@ class ShokupanRouter {
2092
2092
  if (ctx.app?.applicationConfig.enableMiddlewareTracking) {
2093
2093
  const duration = performance.now() - startTime;
2094
2094
  const config = ctx.app.applicationConfig;
2095
- try {
2096
- const timestamp = Date.now();
2097
- const key = `${timestamp}-${handler.name || "anonymous"}-${Math.random().toString(36).substring(7)}`;
2098
- await datastore.set("middleware_tracking", key, {
2099
- name: handler.name || "anonymous",
2100
- path: ctx.path,
2101
- timestamp,
2102
- duration,
2103
- file,
2104
- line,
2105
- error: error ? String(error) : void 0,
2106
- metadata: {
2107
- isBuiltin: handler.isBuiltin,
2108
- pluginName: handler.pluginName
2095
+ Promise.resolve().then(async () => {
2096
+ try {
2097
+ const timestamp = Date.now();
2098
+ const key = `${timestamp}-${handler.name || "anonymous"}-${Math.random().toString(36).substring(7)}`;
2099
+ await datastore.set("middleware_tracking", key, {
2100
+ name: handler.name || "anonymous",
2101
+ path: ctx.path,
2102
+ timestamp,
2103
+ duration,
2104
+ file,
2105
+ line,
2106
+ error: error ? String(error) : void 0,
2107
+ metadata: {
2108
+ isBuiltin: handler.isBuiltin,
2109
+ pluginName: handler.pluginName
2110
+ }
2111
+ });
2112
+ const ttl = config.middlewareTrackingTTL ?? 864e5;
2113
+ const maxCapacity = config.middlewareTrackingMaxCapacity ?? 1e4;
2114
+ const cutoff = Date.now() - ttl;
2115
+ await datastore.query(`DELETE middleware_tracking WHERE timestamp < ${cutoff}`);
2116
+ const results = await datastore.query("SELECT count() FROM middleware_tracking GROUP ALL");
2117
+ if (results && results[0] && results[0].count > maxCapacity) {
2118
+ const toDelete = results[0].count - maxCapacity;
2119
+ await datastore.query(`DELETE middleware_tracking ORDER BY timestamp ASC LIMIT ${toDelete}`);
2109
2120
  }
2110
- });
2111
- const ttl = config.middlewareTrackingTTL ?? 864e5;
2112
- const maxCapacity = config.middlewareTrackingMaxCapacity ?? 1e4;
2113
- const cutoff = Date.now() - ttl;
2114
- await datastore.query(`DELETE middleware_tracking WHERE timestamp < ${cutoff}`);
2115
- const results = await datastore.query("SELECT count() FROM middleware_tracking GROUP ALL");
2116
- if (results && results[0] && results[0].count > maxCapacity) {
2117
- const toDelete = results[0].count - maxCapacity;
2118
- await datastore.query(`DELETE middleware_tracking ORDER BY timestamp ASC LIMIT ${toDelete}`);
2121
+ } catch (datastoreError) {
2122
+ console.error("Failed to store middleware tracking:", datastoreError);
2119
2123
  }
2120
- } catch (datastoreError) {
2121
- console.error("Failed to store middleware tracking:", datastoreError);
2122
- }
2124
+ });
2123
2125
  }
2124
2126
  }
2125
2127
  };
@@ -2472,7 +2474,7 @@ class Shokupan extends ShokupanRouter {
2472
2474
  factory = createHttpServer();
2473
2475
  }
2474
2476
  const server = factory ? await factory(serveOptions) : Bun.serve(serveOptions);
2475
- console.log(`Shokupan server listening on http://${server.hostname}:${server.port}`);
2477
+ console.log(`Shokupan server listening on http://${serveOptions.hostname}:${serveOptions.port}`);
2476
2478
  return server;
2477
2479
  }
2478
2480
  [$dispatch](req) {
@@ -3278,8 +3280,8 @@ function validate(config) {
3278
3280
  body = await safelyGetBody(ctx);
3279
3281
  dataToValidate.body = body;
3280
3282
  }
3281
- if (ctx.app?.applicationConfig.hooks?.beforeValidate) {
3282
- await ctx.app.applicationConfig.hooks.beforeValidate(ctx, dataToValidate);
3283
+ if (ctx.app?.hasHook("beforeValidate")) {
3284
+ await ctx.app.executeHook("beforeValidate", ctx, dataToValidate);
3283
3285
  }
3284
3286
  if (validators.params) {
3285
3287
  ctx.params = await validators.params(ctx.params);
@@ -3304,12 +3306,12 @@ function validate(config) {
3304
3306
  });
3305
3307
  ctx.body = validBody;
3306
3308
  }
3307
- if (ctx.app?.applicationConfig.hooks?.afterValidate) {
3309
+ if (ctx.app?.hasHook("afterValidate")) {
3308
3310
  const validatedData = { ...dataToValidate };
3309
3311
  if (config.params) validatedData.params = ctx.params;
3310
3312
  if (config.query) validatedData.query = validQuery;
3311
3313
  if (config.body) validatedData.body = validBody;
3312
- await ctx.app.applicationConfig.hooks.afterValidate(ctx, validatedData);
3314
+ await ctx.app?.executeHook("afterValidate", ctx, validatedData);
3313
3315
  }
3314
3316
  return next();
3315
3317
  };
@@ -3473,7 +3475,8 @@ function enableOpenApiValidation(app) {
3473
3475
  }
3474
3476
  const eta = new eta$2.Eta();
3475
3477
  class ScalarPlugin extends ShokupanRouter {
3476
- constructor(pluginOptions) {
3478
+ constructor(pluginOptions = {}) {
3479
+ pluginOptions.config ??= {};
3477
3480
  super();
3478
3481
  this.pluginOptions = pluginOptions;
3479
3482
  this.init();
@@ -3492,8 +3495,7 @@ class ScalarPlugin extends ShokupanRouter {
3492
3495
 
3493
3496
  <body>
3494
3497
  <div id="app"></div>
3495
-
3496
- <script src="<%= it.path %>scalar.js"><\/script>
3498
+ <script src="https://cdn.jsdelivr.net/npm/@scalar/api-reference"><\/script>
3497
3499
  <script>
3498
3500
  Scalar.createApiReference('#app', [{ ...<%~ JSON.stringify(it.config.baseDocument) %>,
3499
3501
  url: "<%= it.path %>openapi.json",
@@ -3504,9 +3506,6 @@ class ScalarPlugin extends ShokupanRouter {
3504
3506
 
3505
3507
  </html>`, { path: path2, config: this.pluginOptions }));
3506
3508
  });
3507
- this.get("/scalar.js", (ctx) => {
3508
- return ctx.file(__dirname + "/../../node_modules/@scalar/api-reference/dist/browser/standalone.js");
3509
- });
3510
3509
  this.get("/openapi.json", async (ctx) => {
3511
3510
  let spec;
3512
3511
  if (this.root.openApiSpec) {