shokupan 0.6.1 → 0.9.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 (81) hide show
  1. package/README.md +55 -2
  2. package/dist/{openapi-analyzer-Bei1sVWp.cjs → analyzer-Bei1sVWp.cjs} +1 -1
  3. package/dist/analyzer-Bei1sVWp.cjs.map +1 -0
  4. package/dist/{openapi-analyzer-Ce_7JxZh.js → analyzer-Ce_7JxZh.js} +1 -1
  5. package/dist/analyzer-Ce_7JxZh.js.map +1 -0
  6. package/dist/cli.cjs +2 -2
  7. package/dist/cli.cjs.map +1 -1
  8. package/dist/cli.js +1 -1
  9. package/dist/cli.js.map +1 -1
  10. package/dist/context.d.ts +58 -23
  11. package/dist/{server-adapter-DFhwlK8e.cjs → http-server-BEMPIs33.cjs} +4 -2
  12. package/dist/http-server-BEMPIs33.cjs.map +1 -0
  13. package/dist/{server-adapter-0xH174zz.js → http-server-CCeagTyU.js} +4 -2
  14. package/dist/http-server-CCeagTyU.js.map +1 -0
  15. package/dist/index.cjs +1940 -917
  16. package/dist/index.cjs.map +1 -1
  17. package/dist/index.d.ts +18 -17
  18. package/dist/index.js +1948 -925
  19. package/dist/index.js.map +1 -1
  20. package/dist/middleware.d.ts +1 -1
  21. package/dist/plugins/{auth.d.ts → application/auth.d.ts} +72 -3
  22. package/dist/plugins/application/cluster.d.ts +33 -0
  23. package/dist/plugins/{failed-request-recorder.d.ts → application/dashboard/failed-request-recorder.d.ts} +1 -1
  24. package/dist/plugins/application/dashboard/metrics-collector.d.ts +12 -0
  25. package/dist/plugins/application/dashboard/plugin.d.ts +42 -0
  26. package/dist/plugins/application/dashboard/static/charts.js +328 -0
  27. package/dist/plugins/application/dashboard/static/failures.js +85 -0
  28. package/dist/plugins/application/dashboard/static/graph.mjs +523 -0
  29. package/dist/plugins/application/dashboard/static/poll.js +146 -0
  30. package/dist/plugins/application/dashboard/static/reactflow.css +18 -0
  31. package/dist/plugins/application/dashboard/static/registry.css +131 -0
  32. package/dist/plugins/application/dashboard/static/registry.js +269 -0
  33. package/dist/plugins/application/dashboard/static/requests.js +118 -0
  34. package/dist/plugins/application/dashboard/static/scrollbar.css +24 -0
  35. package/dist/plugins/application/dashboard/static/styles.css +175 -0
  36. package/dist/plugins/application/dashboard/static/tables.js +92 -0
  37. package/dist/plugins/application/dashboard/static/tabs.js +113 -0
  38. package/dist/plugins/application/dashboard/static/tabulator.css +66 -0
  39. package/dist/plugins/application/dashboard/template.eta +246 -0
  40. package/dist/plugins/{server-adapter.d.ts → application/http-server.d.ts} +1 -1
  41. package/dist/plugins/{idempotency → application/idempotency}/plugin.d.ts +7 -1
  42. package/dist/plugins/{openapi.d.ts → application/openapi/openapi.d.ts} +2 -2
  43. package/dist/plugins/application/scalar.d.ts +36 -0
  44. package/dist/plugins/application/socket-io.d.ts +14 -0
  45. package/dist/plugins/middleware/compression.d.ts +17 -0
  46. package/dist/plugins/middleware/cors.d.ts +34 -0
  47. package/dist/plugins/{express.d.ts → middleware/express.d.ts} +1 -1
  48. package/dist/plugins/{openapi-validator.d.ts → middleware/openapi-validator.d.ts} +2 -2
  49. package/dist/plugins/middleware/proxy.d.ts +37 -0
  50. package/dist/plugins/middleware/rate-limit.d.ts +58 -0
  51. package/dist/plugins/{security-headers.d.ts → middleware/security-headers.d.ts} +51 -1
  52. package/dist/plugins/{serve-static.d.ts → middleware/serve-static.d.ts} +1 -1
  53. package/dist/plugins/{session.d.ts → middleware/session.d.ts} +89 -3
  54. package/dist/plugins/{validation.d.ts → middleware/validation.d.ts} +6 -1
  55. package/dist/router.d.ts +17 -5
  56. package/dist/shokupan.d.ts +31 -5
  57. package/dist/util/async-hooks.d.ts +8 -2
  58. package/dist/util/datastore.d.ts +4 -3
  59. package/dist/{decorators.d.ts → util/decorators.d.ts} +6 -1
  60. package/dist/util/http-error.d.ts +38 -0
  61. package/dist/util/http-status.d.ts +32 -0
  62. package/dist/util/instrumentation.d.ts +1 -1
  63. package/dist/{request.d.ts → util/request.d.ts} +1 -1
  64. package/dist/util/symbol.d.ts +34 -0
  65. package/dist/{router → util}/trie.d.ts +1 -1
  66. package/dist/{types.d.ts → util/types.d.ts} +38 -2
  67. package/package.json +9 -6
  68. package/dist/openapi-analyzer-Bei1sVWp.cjs.map +0 -1
  69. package/dist/openapi-analyzer-Ce_7JxZh.js.map +0 -1
  70. package/dist/plugins/compression.d.ts +0 -5
  71. package/dist/plugins/cors.d.ts +0 -11
  72. package/dist/plugins/debugview/plugin.d.ts +0 -29
  73. package/dist/plugins/proxy.d.ts +0 -11
  74. package/dist/plugins/rate-limit.d.ts +0 -15
  75. package/dist/plugins/scalar.d.ts +0 -15
  76. package/dist/server-adapter-0xH174zz.js.map +0 -1
  77. package/dist/server-adapter-DFhwlK8e.cjs.map +0 -1
  78. package/dist/symbol.d.ts +0 -15
  79. /package/dist/{analysis/openapi-analyzer.d.ts → plugins/application/openapi/analyzer.d.ts} +0 -0
  80. /package/dist/{di.d.ts → util/di.d.ts} +0 -0
  81. /package/dist/{response.d.ts → util/response.d.ts} +0 -0
@@ -1,43 +1,124 @@
1
1
  import { EventEmitter } from 'events';
2
- import { ShokupanContext } from '../context';
3
- import { Middleware } from '../types';
2
+ import { ShokupanContext } from '../../context';
3
+ import { Middleware } from '../../util/types';
4
4
  export interface SessionData {
5
5
  cookie: Cookie;
6
6
  [key: string]: any;
7
7
  }
8
8
  export interface SessionCookieOptions {
9
+ /**
10
+ * Maximum age of the session cookie in milliseconds.
11
+ */
9
12
  maxAge?: number;
13
+ /**
14
+ * Whether the session cookie should be signed.
15
+ */
10
16
  signed?: boolean;
17
+ /**
18
+ * Expiration date of the session cookie.
19
+ */
11
20
  expires?: Date;
21
+ /**
22
+ * Whether the session cookie should be HTTP-only.
23
+ */
12
24
  httpOnly?: boolean;
25
+ /**
26
+ * Path of the session cookie.
27
+ */
13
28
  path?: string;
29
+ /**
30
+ * Domain of the session cookie.
31
+ */
14
32
  domain?: string;
33
+ /**
34
+ * Whether the session cookie should be secure.
35
+ */
15
36
  secure?: boolean | 'auto';
37
+ /**
38
+ * SameSite attribute of the session cookie.
39
+ */
16
40
  sameSite?: boolean | 'lax' | 'strict' | 'none';
41
+ /**
42
+ * Priority of the session cookie.
43
+ */
17
44
  priority?: 'low' | 'medium' | 'high';
18
45
  }
19
46
  export interface SessionOptions {
47
+ /**
48
+ * Secret used to sign the session cookie.
49
+ */
20
50
  secret: string | string[];
51
+ /**
52
+ * Name of the session cookie.
53
+ */
21
54
  name?: string;
55
+ /**
56
+ * Store to use for session data.
57
+ */
22
58
  store?: Store;
59
+ /**
60
+ * Options for the session cookie.
61
+ */
23
62
  cookie?: SessionCookieOptions;
63
+ /**
64
+ * Function to generate a session ID.
65
+ */
24
66
  genid?: (ctx: ShokupanContext) => string;
67
+ /**
68
+ * Whether to force a session identifier cookie to be set on every response.
69
+ */
25
70
  resave?: boolean;
71
+ /**
72
+ * Whether to save the session on every request.
73
+ */
26
74
  saveUninitialized?: boolean;
75
+ /**
76
+ * Whether to update the session cookie on every request.
77
+ */
27
78
  rolling?: boolean;
79
+ /**
80
+ * Whether to destroy or keep the session on logout.
81
+ */
28
82
  unset?: 'destroy' | 'keep';
29
83
  }
30
84
  export interface Store extends EventEmitter {
85
+ /**
86
+ * Retrieves a session by ID.
87
+ */
31
88
  get(sid: string, callback: (err: any, session?: SessionData | null) => void): void;
89
+ /**
90
+ * Stores a session.
91
+ */
32
92
  set(sid: string, session: SessionData, callback?: (err?: any) => void): void;
93
+ /**
94
+ * Destroys a session.
95
+ */
33
96
  destroy(sid: string, callback?: (err?: any) => void): void;
97
+ /**
98
+ * Touches a session.
99
+ */
34
100
  touch?(sid: string, session: SessionData, callback?: (err?: any) => void): void;
101
+ /**
102
+ * Retrieves all sessions.
103
+ */
35
104
  all?(callback: (err: any, obj?: {
36
105
  [sid: string]: SessionData;
37
106
  } | null) => void): void;
107
+ /**
108
+ * Retrieves the number of sessions.
109
+ */
38
110
  length?(callback: (err: any, length?: number) => void): void;
111
+ /**
112
+ * Clears all sessions.
113
+ */
39
114
  clear?(callback?: (err?: any) => void): void;
115
+ /**
116
+ * Loads a session.
117
+ */
40
118
  load?(sid: string, fn: (err: any, session?: SessionData | null) => void): void;
119
+ /**
120
+ * Creates a session.
121
+ */
41
122
  createSession?(req: any, session: SessionData): SessionData;
42
123
  }
43
124
  declare class Cookie implements SessionCookieOptions {
@@ -76,12 +157,17 @@ export interface SessionContext {
76
157
  sessionID: string;
77
158
  sessionStore: Store;
78
159
  }
79
- declare module "../context" {
160
+ declare module "../../context" {
80
161
  interface ShokupanContext {
81
162
  session: SessionContext['session'];
82
163
  sessionID: string;
83
164
  sessionStore: Store;
84
165
  }
85
166
  }
167
+ /**
168
+ * Session middleware.
169
+ * @param options Session options
170
+ * @returns Middleware function
171
+ */
86
172
  export declare function Session(options: SessionOptions): Middleware;
87
173
  export {};
@@ -1,4 +1,4 @@
1
- import { Middleware } from '../types';
1
+ import { Middleware } from '../../util/types';
2
2
  export interface ValidationConfig {
3
3
  body?: any;
4
4
  query?: any;
@@ -15,4 +15,9 @@ export declare const valibot: (schema: any, parser: Function) => {
15
15
  schema: any;
16
16
  parser: Function;
17
17
  };
18
+ /**
19
+ * Validation middleware.
20
+ * @param config Validation configuration
21
+ * @returns Middleware function
22
+ */
18
23
  export declare function validate(config: ValidationConfig): Middleware;
package/dist/router.d.ts CHANGED
@@ -1,8 +1,7 @@
1
1
  import { ShokupanContext } from './context';
2
2
  import { Shokupan } from './shokupan';
3
- import { $appRoot, $childControllers, $childRouters, $isApplication, $isMounted, $isRouter, $mountPath, $parent, $routes } from './symbol';
4
- import { GuardAPISpec, JSXRenderer, Method, MethodAPISpec, Middleware, OpenAPIOptions, ProcessResult, RequestOptions, RouteMetadata, RouteParams, ShokupanController, ShokupanHandler, ShokupanHooks, ShokupanRoute, ShokupanRouteConfig, StaticServeOptions } from './types';
5
- type HeadersInit = Headers | Record<string, string> | [string, string][];
3
+ import { $appRoot, $childControllers, $childRouters, $isApplication, $isMounted, $isRouter, $mountPath, $parent, $routes } from './util/symbol';
4
+ import { GuardAPISpec, HeadersInit, JSXRenderer, Method, MethodAPISpec, Middleware, OpenAPIOptions, ProcessResult, RequestOptions, RouteMetadata, RouteParams, ShokupanController, ShokupanHandler, ShokupanHooks, ShokupanRoute, ShokupanRouteConfig, StaticServeOptions } from './util/types';
6
5
  export declare const RouterRegistry: Map<string, ShokupanRouter<any>>;
7
6
  export declare const ShokupanApplicationTree: {};
8
7
  /**
@@ -92,6 +91,9 @@ export declare class ShokupanRouter<T extends Record<string, any> = Record<strin
92
91
  autoBackpressureLevel?: number;
93
92
  enableMiddlewareTracking?: boolean;
94
93
  middlewareTrackingMaxCapacity?: number;
94
+ enableHTTPBridge?: boolean;
95
+ websocketErrorHandler?: (err: any, ctx: ShokupanContext<Record<string, any>, Record<string, string>>) => void | Promise<void>;
96
+ idGenerator?: () => string;
95
97
  middlewareTrackingTTL?: number;
96
98
  httpLogger?: (ctx: ShokupanContext<Record<string, any>, Record<string, string>>) => void;
97
99
  logger?: {
@@ -106,7 +108,7 @@ export declare class ShokupanRouter<T extends Record<string, any> = Record<strin
106
108
  requestTimeout?: number;
107
109
  writeTimeout?: number;
108
110
  renderer?: JSXRenderer;
109
- serverFactory?: import('./types').ServerFactory;
111
+ serverFactory?: import('.').ServerFactory;
110
112
  hooks?: {
111
113
  onError?: (ctx: ShokupanContext<Record<string, any>, Record<string, string>>, error: unknown) => void | Promise<void>;
112
114
  onRequestStart?: (ctx: ShokupanContext<Record<string, any>, Record<string, string>>) => void | Promise<void>;
@@ -137,6 +139,7 @@ export declare class ShokupanRouter<T extends Record<string, any> = Record<strin
137
139
  private trie;
138
140
  metadata?: RouteMetadata;
139
141
  private currentGuards;
142
+ private eventHandlers;
140
143
  getComponentRegistry(): {
141
144
  metadata: RouteMetadata;
142
145
  middleware: {
@@ -175,6 +178,14 @@ export declare class ShokupanRouter<T extends Record<string, any> = Record<strin
175
178
  };
176
179
  constructor(config?: ShokupanRouteConfig);
177
180
  private isRouterInstance;
181
+ /**
182
+ * Registers an event handler for WebSocket.
183
+ */
184
+ event(name: string, handler: ShokupanHandler<T>): this;
185
+ /**
186
+ * Finds an event handler(s) by name.
187
+ */
188
+ findEvent(name: string): ShokupanHandler<T>[] | null;
178
189
  /**
179
190
  * Mounts a controller instance to a path prefix.
180
191
  *
@@ -212,6 +223,8 @@ export declare class ShokupanRouter<T extends Record<string, any> = Record<strin
212
223
  */
213
224
  testRequest(options: RequestOptions): Promise<ProcessResult>;
214
225
  private wrapWithHooks;
226
+ private mountRouter;
227
+ private scanControllerRoutes;
215
228
  /**
216
229
  * Find a route matching the given method and path.
217
230
  * @param method HTTP method
@@ -388,4 +401,3 @@ export declare class ShokupanRouter<T extends Record<string, any> = Record<strin
388
401
  private ensureHooksInitialized;
389
402
  runHooks(name: keyof ShokupanHooks, ...args: any[]): Promise<void>;
390
403
  }
391
- export {};
@@ -1,8 +1,8 @@
1
- import { ShokupanRequest } from './request';
2
- import { ShokupanRouter } from './router';
3
- import { $dispatch } from './symbol';
4
- import { Middleware, ProcessResult, RequestOptions, ShokupanConfig } from './types';
1
+ import { $dispatch } from './util/symbol';
2
+ import { Middleware, ProcessResult, RequestOptions, ShokupanConfig, ShokupanPlugin } from './util/types';
5
3
  import { Server } from 'bun';
4
+ import { ShokupanRouter } from './router';
5
+ import { ShokupanRequest } from './util/request';
6
6
  /**
7
7
  * Shokupan Application
8
8
  *
@@ -72,6 +72,7 @@ export declare class Shokupan<T = any> extends ShokupanRouter<T> {
72
72
  openApiSpec?: any;
73
73
  private composedMiddleware?;
74
74
  private cpuMonitor?;
75
+ private server?;
75
76
  get logger(): {
76
77
  verbose?: boolean;
77
78
  info?: (msg: string, props: Record<string, any>) => void;
@@ -85,6 +86,12 @@ export declare class Shokupan<T = any> extends ShokupanRouter<T> {
85
86
  * Adds middleware to the application.
86
87
  */
87
88
  use(middleware: Middleware): this;
89
+ /**
90
+ * Registers a plugin.
91
+ */
92
+ register(plugin: ShokupanPlugin, options?: {
93
+ path?: string;
94
+ }): this;
88
95
  private startupHooks;
89
96
  /**
90
97
  * Registers a callback to be executed before the server starts listening.
@@ -102,7 +109,26 @@ export declare class Shokupan<T = any> extends ShokupanRouter<T> {
102
109
  * @param port - The port to listen on. If not specified, the port from the configuration is used. If that is not specified, port 3000 is used.
103
110
  * @returns The server instance.
104
111
  */
105
- listen(port?: number): Promise<Server | import('http').Server<typeof import('http').IncomingMessage, typeof import('http').ServerResponse>>;
112
+ listen(port?: number): Promise<Server>;
113
+ /**
114
+ * Stops the application server.
115
+ *
116
+ * This method gracefully shuts down the server and stops any running monitors.
117
+ * Works transparently in both Bun and Node.js runtimes.
118
+ *
119
+ * @returns A promise that resolves when the server has been stopped.
120
+ *
121
+ * @example
122
+ * ```typescript
123
+ * const app = new Shokupan();
124
+ * const server = await app.listen(3000);
125
+ *
126
+ * // Later, when you want to stop the server
127
+ * await app.stop();
128
+ * ```
129
+ * @param closeActiveConnections — Immediately terminate in-flight requests, websockets, and stop accepting new connections.
130
+ */
131
+ stop(closeActiveConnections?: boolean): Promise<void>;
106
132
  [$dispatch](req: ShokupanRequest<T>): Promise<Response>;
107
133
  /**
108
134
  * Processes a request by wrapping the standard fetch method.
@@ -1,3 +1,9 @@
1
1
  import { AsyncLocalStorage } from 'node:async_hooks';
2
- export declare const asyncContext: AsyncLocalStorage<Map<string, any>>;
3
- export declare function runInContext<T>(callback: () => T, initialStore?: Map<string, any>): T;
2
+ import { Span } from '@opentelemetry/api';
3
+ export declare class RequestContextStore {
4
+ request?: Request;
5
+ span?: Span;
6
+ [key: string]: any;
7
+ }
8
+ export declare const asyncContext: AsyncLocalStorage<RequestContextStore>;
9
+ export declare function runInContext<T>(callback: () => T, initialStore?: RequestContextStore): T;
@@ -1,6 +1,7 @@
1
+ import { RecordId, Range, Table } from 'surrealdb';
1
2
  export declare const datastore: {
2
- get<T extends Record<string, any>>(store: string, key: string): Promise<T>;
3
- set(store: string, key: string, value: any): Promise<any>;
4
- query(query: string, vars?: Record<string, unknown>): Promise<any>;
3
+ get<T extends Record<string, any>>(recordId: RecordId | Table | Range<any, any>): Promise<T>;
4
+ set(recordId: RecordId, value: Record<string, any>): Promise<any>;
5
+ query<T extends Record<string, any>>(query: string, vars?: Record<string, unknown>): Promise<T>;
5
6
  readonly ready: Promise<any>;
6
7
  };
@@ -1,4 +1,4 @@
1
- import { RateLimitOptions } from './plugins/rate-limit';
1
+ import { RateLimitOptions } from '../plugins/middleware/rate-limit';
2
2
  import { GuardAPISpec, MethodAPISpec, Middleware } from './types';
3
3
  /**
4
4
  * Class Decorator: Defines the base path for a controller.
@@ -68,6 +68,11 @@ export declare const Head: (path?: string) => (target: any, propertyKey: string,
68
68
  * Decorator: Binds a method to ANY HTTP verb.
69
69
  */
70
70
  export declare const All: (path?: string) => (target: any, propertyKey: string, descriptor: PropertyDescriptor) => void;
71
+ /**
72
+ * Decorator: Binds a method to the WebSocket event.
73
+ * @param eventName The name of the event to listen for.
74
+ */
75
+ export declare function Event(eventName: string): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => void;
71
76
  /**
72
77
  * Decorator: Applies a rate limit to a class or method.
73
78
  */
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Standard HTTP Error class with status code.
3
+ * This standardizes on the `status` property instead of dual `status`/`statusCode`.
4
+ */
5
+ export declare class HttpError extends Error {
6
+ readonly status: number;
7
+ constructor(message: string, status: number);
8
+ }
9
+ /**
10
+ * Extracts HTTP status code from an error object.
11
+ * Supports both `status` and `statusCode` properties for backward compatibility.
12
+ * Defaults to 500 (Internal Server Error) if no status is found.
13
+ *
14
+ * @param err - Error object (may have `status` or `statusCode` property)
15
+ * @returns HTTP status code
16
+ */
17
+ export declare function getErrorStatus(err: any): number;
18
+ /**
19
+ * Common HTTP Errors
20
+ */
21
+ export declare class BadRequestError extends HttpError {
22
+ constructor(message?: string);
23
+ }
24
+ export declare class UnauthorizedError extends HttpError {
25
+ constructor(message?: string);
26
+ }
27
+ export declare class ForbiddenError extends HttpError {
28
+ constructor(message?: string);
29
+ }
30
+ export declare class NotFoundError extends HttpError {
31
+ constructor(message?: string);
32
+ }
33
+ export declare class InternalServerError extends HttpError {
34
+ constructor(message?: string);
35
+ }
36
+ export declare class EventError extends HttpError {
37
+ constructor(message?: string);
38
+ }
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Common HTTP Status Codes
3
+ * Use these constants instead of magic numbers for better readability
4
+ */
5
+ export declare const HTTP_STATUS: {
6
+ readonly OK: 200;
7
+ readonly CREATED: 201;
8
+ readonly ACCEPTED: 202;
9
+ readonly NO_CONTENT: 204;
10
+ readonly MOVED_PERMANENTLY: 301;
11
+ readonly FOUND: 302;
12
+ readonly SEE_OTHER: 303;
13
+ readonly NOT_MODIFIED: 304;
14
+ readonly TEMPORARY_REDIRECT: 307;
15
+ readonly PERMANENT_REDIRECT: 308;
16
+ readonly BAD_REQUEST: 400;
17
+ readonly UNAUTHORIZED: 401;
18
+ readonly FORBIDDEN: 403;
19
+ readonly NOT_FOUND: 404;
20
+ readonly METHOD_NOT_ALLOWED: 405;
21
+ readonly REQUEST_TIMEOUT: 408;
22
+ readonly CONFLICT: 409;
23
+ readonly UNPROCESSABLE_ENTITY: 422;
24
+ readonly TOO_MANY_REQUESTS: 429;
25
+ readonly INTERNAL_SERVER_ERROR: 500;
26
+ readonly NOT_IMPLEMENTED: 501;
27
+ readonly BAD_GATEWAY: 502;
28
+ readonly SERVICE_UNAVAILABLE: 503;
29
+ readonly GATEWAY_TIMEOUT: 504;
30
+ };
31
+ export declare const VALID_HTTP_STATUSES: Set<number>;
32
+ export declare const VALID_REDIRECT_STATUSES: Set<number>;
@@ -1,4 +1,4 @@
1
- import { Middleware, ShokupanHandler } from '../types';
1
+ import { Middleware, ShokupanHandler } from './types';
2
2
  /**
3
3
  * Wraps a middleware function with an OpenTelemetry span.
4
4
  */
@@ -2,7 +2,7 @@ import { Method } from './types';
2
2
  export type ShokupanRequestProps = {
3
3
  method: Method;
4
4
  url: string;
5
- headers: Headers;
5
+ headers: Headers | Record<string, string>;
6
6
  body: any;
7
7
  };
8
8
  /**
@@ -0,0 +1,34 @@
1
+ export declare const $isApplication: unique symbol;
2
+ export declare const $appRoot: unique symbol;
3
+ export declare const $isMounted: unique symbol;
4
+ export declare const $routeMethods: unique symbol;
5
+ export declare const $eventMethods: unique symbol;
6
+ export declare const $routeArgs: unique symbol;
7
+ export declare const $controllerPath: unique symbol;
8
+ export declare const $middleware: unique symbol;
9
+ export declare const $isRouter: unique symbol;
10
+ export declare const $parent: unique symbol;
11
+ export declare const $childRouters: unique symbol;
12
+ export declare const $childControllers: unique symbol;
13
+ export declare const $mountPath: unique symbol;
14
+ export declare const $dispatch: unique symbol;
15
+ export declare const $routes: unique symbol;
16
+ export declare const $routeSpec: unique symbol;
17
+ export declare const $url: unique symbol;
18
+ export declare const $requestId: unique symbol;
19
+ export declare const $debug: unique symbol;
20
+ export declare const $finalResponse: unique symbol;
21
+ export declare const $rawBody: unique symbol;
22
+ export declare const $cachedBody: unique symbol;
23
+ export declare const $bodyType: unique symbol;
24
+ export declare const $bodyParsed: unique symbol;
25
+ export declare const $bodyParseError: unique symbol;
26
+ export declare const $routeMatched: unique symbol;
27
+ export declare const $cachedHostname: unique symbol;
28
+ export declare const $cachedProtocol: unique symbol;
29
+ export declare const $cachedHost: unique symbol;
30
+ export declare const $cachedOrigin: unique symbol;
31
+ export declare const $cachedQuery: unique symbol;
32
+ export declare const $ws: unique symbol;
33
+ export declare const $socket: unique symbol;
34
+ export declare const $io: unique symbol;
@@ -1,4 +1,4 @@
1
- import { Method, ShokupanHandler } from '../types';
1
+ import { Method, ShokupanHandler } from './types';
2
2
  export interface RouteMatch<T = any> {
3
3
  handler: ShokupanHandler<T>;
4
4
  params: Record<string, string>;
@@ -1,8 +1,15 @@
1
1
  import { OpenAPI } from '@scalar/openapi-types';
2
2
  import { Server } from 'bun';
3
3
  import { Server as NodeServer } from 'node:http';
4
- import { ShokupanContext } from './context';
4
+ import { ShokupanContext } from '../context';
5
5
  import { $isRouter } from './symbol';
6
+ export type HeadersInit = Headers | Record<string, string> | [string, string][];
7
+ export interface ShokupanPluginOptions {
8
+ path?: string;
9
+ }
10
+ export interface ShokupanPlugin {
11
+ onInit: (app: any, options?: ShokupanPluginOptions) => void | Promise<void>;
12
+ }
6
13
  export type DeepPartial<T> = T extends Function ? T : T extends object ? {
7
14
  [P in keyof T]?: DeepPartial<T[P]>;
8
15
  } : T;
@@ -76,7 +83,9 @@ export interface CookieOptions {
76
83
  sameSite?: boolean | 'lax' | 'strict' | 'none' | 'Lax' | 'Strict' | 'None';
77
84
  priority?: 'low' | 'medium' | 'high' | 'Low' | 'Medium' | 'High';
78
85
  }
79
- export type ShokupanHandler<State extends Record<string, any> = Record<string, any>, Params extends Record<string, string> = Record<string, string>> = (ctx: ShokupanContext<State, Params>, next?: NextFn) => Promise<any> | any;
86
+ export type ShokupanHandler<State extends Record<string, any> = Record<string, any>, Params extends Record<string, string> = Record<string, string>> = ((ctx: ShokupanContext<State, Params>, next?: NextFn) => Promise<any> | any) & {
87
+ originalHandler?: ShokupanHandler<State, Params>;
88
+ };
80
89
  export declare const HTTPMethods: string[];
81
90
  export type Method = "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "OPTIONS" | "HEAD" | "ALL";
82
91
  export declare enum RouteParamType {
@@ -282,6 +291,33 @@ export type ShokupanConfig<T extends Record<string, any> = Record<string, any>>
282
291
  * @default 10000
283
292
  */
284
293
  middlewareTrackingMaxCapacity?: number;
294
+ /**
295
+ * Whether to enable the HTTP bridge for WebSocket.
296
+ * This enables websocket messages to run through the HTTP server.
297
+ * e.g.
298
+ * ```json
299
+ * {
300
+ * "method": "POST",
301
+ * "path": "/api/v1/myHttpEndpoint",
302
+ * "headers": {},
303
+ * "body": {
304
+ * "type": "text",
305
+ * "data": "Hello, world!"
306
+ * }
307
+ * }
308
+ * ```
309
+ * @default false
310
+ */
311
+ enableHTTPBridge?: boolean;
312
+ /**
313
+ * Handler for WebSocket events that throw an exception.
314
+ */
315
+ websocketErrorHandler?: (err: any, ctx: ShokupanContext<T>) => void | Promise<void>;
316
+ /**
317
+ * Unique ID generator function for requests.
318
+ * @default nanoid
319
+ */
320
+ idGenerator?: () => string;
285
321
  /**
286
322
  * Time-to-live for middleware tracking entries in milliseconds.
287
323
  * Entries older than this will be cleaned up.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shokupan",
3
- "version": "0.6.1",
3
+ "version": "0.9.0",
4
4
  "description": "Shokupan is a low-lift modern web framework for Bun.",
5
5
  "author": "Andrew G. Knackstedt",
6
6
  "publishConfig": {
@@ -22,12 +22,12 @@
22
22
  ],
23
23
  "type": "module",
24
24
  "scripts": {
25
- "dev": "bun --watch --inspect src/example/main.ts",
25
+ "dev": "bun --watch --inspect examples/full/main.ts",
26
26
  "debug:otel": "sh scripts/debug-otel.sh",
27
27
  "docs": "cd docs && bun run dev",
28
28
  "build": "vite build",
29
- "bench": "cd src/benchmarking && bun runner.ts",
30
- "bench:advanced": "cd src/benchmarking && bun advanced-runner.ts",
29
+ "bench": "cd benchmarking && bun runner.ts",
30
+ "bench:advanced": "cd benchmarking && bun advanced-runner.ts",
31
31
  "retag": "git push origin :refs/tags/v$(node -p \"require('./package.json').version\") 2>/dev/null || true && git tag -d v$(node -p \"require('./package.json').version\") 2>/dev/null || true && git tag v$(node -p \"require('./package.json').version\") && git push origin v$(node -p \"require('./package.json').version\") --force"
32
32
  },
33
33
  "bin": {
@@ -65,9 +65,13 @@
65
65
  "@opentelemetry/sdk-trace-node": "^2.2.0",
66
66
  "@opentelemetry/semantic-conventions": "^1.38.0",
67
67
  "@scalar/openapi-types": "^0.5.3",
68
+ "nanoid": "^5.1.6",
69
+ "socket.io": "^4.8.3",
68
70
  "tslib": "^2.8.1"
69
71
  },
70
72
  "peerDependencies": {
73
+ "@scalar/api-reference": "^1.0.0",
74
+ "@surrealdb/node": "^2.4.0",
71
75
  "ajv": "^8.0.0",
72
76
  "ajv-formats": "^3.0.0",
73
77
  "arctic": "^3",
@@ -78,8 +82,6 @@
78
82
  "parse-json": "^8.0.0",
79
83
  "reflect-metadata": "^0.2.0",
80
84
  "secure-json-parse": "^4.0.0",
81
- "@scalar/api-reference": "^1.0.0",
82
- "@surrealdb/node": "^2.4.0",
83
85
  "surrealdb": "^2.0.0-alpha.14"
84
86
  },
85
87
  "peerDependenciesMeta": {
@@ -150,6 +152,7 @@
150
152
  "valibot": "^1.2.0",
151
153
  "vite": "^7.3.0",
152
154
  "vite-plugin-dts": "^4.5.4",
155
+ "vite-plugin-static-copy": "^3.1.4",
153
156
  "zod": "^4.2.1"
154
157
  }
155
158
  }