shokupan 0.7.0 → 0.10.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 (66) hide show
  1. package/README.md +53 -0
  2. package/dist/analyzer-BqIe1p0R.js +35 -0
  3. package/dist/analyzer-BqIe1p0R.js.map +1 -0
  4. package/dist/analyzer-CKLGLFtx.cjs +35 -0
  5. package/dist/analyzer-CKLGLFtx.cjs.map +1 -0
  6. package/dist/{analyzer-Ce_7JxZh.js → analyzer.impl-CV6W1Eq7.js} +238 -21
  7. package/dist/analyzer.impl-CV6W1Eq7.js.map +1 -0
  8. package/dist/{analyzer-Bei1sVWp.cjs → analyzer.impl-D9Yi1Hax.cjs} +237 -20
  9. package/dist/analyzer.impl-D9Yi1Hax.cjs.map +1 -0
  10. package/dist/cli.cjs +1 -1
  11. package/dist/cli.js +1 -1
  12. package/dist/context.d.ts +69 -22
  13. package/dist/{http-server-DFhwlK8e.cjs → http-server-BEMPIs33.cjs} +4 -2
  14. package/dist/http-server-BEMPIs33.cjs.map +1 -0
  15. package/dist/{http-server-0xH174zz.js → http-server-CCeagTyU.js} +4 -2
  16. package/dist/http-server-CCeagTyU.js.map +1 -0
  17. package/dist/index.cjs +2411 -329
  18. package/dist/index.cjs.map +1 -1
  19. package/dist/index.d.ts +3 -0
  20. package/dist/index.js +2390 -308
  21. package/dist/index.js.map +1 -1
  22. package/dist/plugins/application/api-explorer/plugin.d.ts +9 -0
  23. package/dist/plugins/application/api-explorer/static/explorer-client.mjs +880 -0
  24. package/dist/plugins/application/api-explorer/static/style.css +767 -0
  25. package/dist/plugins/application/api-explorer/static/theme.css +128 -0
  26. package/dist/plugins/application/asyncapi/generator.d.ts +3 -0
  27. package/dist/plugins/application/asyncapi/plugin.d.ts +15 -0
  28. package/dist/plugins/application/asyncapi/static/asyncapi-client.mjs +748 -0
  29. package/dist/plugins/application/asyncapi/static/style.css +565 -0
  30. package/dist/plugins/application/asyncapi/static/theme.css +128 -0
  31. package/dist/plugins/application/auth.d.ts +3 -1
  32. package/dist/plugins/application/dashboard/metrics-collector.d.ts +14 -0
  33. package/dist/plugins/application/dashboard/plugin.d.ts +25 -9
  34. package/dist/plugins/application/dashboard/static/charts.js +328 -0
  35. package/dist/plugins/application/dashboard/static/failures.js +85 -0
  36. package/dist/plugins/application/dashboard/static/graph.mjs +523 -0
  37. package/dist/plugins/application/dashboard/static/poll.js +146 -0
  38. package/dist/plugins/application/dashboard/static/reactflow.css +18 -0
  39. package/dist/plugins/application/dashboard/static/registry.css +78 -0
  40. package/dist/plugins/application/dashboard/static/registry.js +269 -0
  41. package/dist/plugins/application/dashboard/static/requests.js +118 -0
  42. package/dist/plugins/application/dashboard/static/styles.css +184 -0
  43. package/dist/plugins/application/dashboard/static/tables.js +92 -0
  44. package/dist/plugins/application/dashboard/static/tabs.js +113 -0
  45. package/dist/plugins/application/dashboard/static/tabulator.css +118 -0
  46. package/dist/plugins/application/dashboard/static/theme.css +128 -0
  47. package/dist/plugins/application/graphql-apollo.d.ts +33 -0
  48. package/dist/plugins/application/graphql-yoga.d.ts +25 -0
  49. package/dist/plugins/application/openapi/analyzer.d.ts +12 -119
  50. package/dist/plugins/application/openapi/analyzer.impl.d.ts +167 -0
  51. package/dist/plugins/application/scalar.d.ts +9 -2
  52. package/dist/plugins/application/socket-io.d.ts +14 -0
  53. package/dist/router.d.ts +92 -51
  54. package/dist/shokupan.d.ts +34 -8
  55. package/dist/util/datastore.d.ts +71 -6
  56. package/dist/util/decorators.d.ts +7 -2
  57. package/dist/util/http-error.d.ts +38 -0
  58. package/dist/util/http-status.d.ts +30 -0
  59. package/dist/util/request.d.ts +1 -1
  60. package/dist/util/symbol.d.ts +19 -0
  61. package/dist/util/types.d.ts +126 -4
  62. package/package.json +38 -15
  63. package/dist/analyzer-Bei1sVWp.cjs.map +0 -1
  64. package/dist/analyzer-Ce_7JxZh.js.map +0 -1
  65. package/dist/http-server-0xH174zz.js.map +0 -1
  66. package/dist/http-server-DFhwlK8e.cjs.map +0 -1
@@ -0,0 +1,167 @@
1
+ /**
2
+ * Route information extracted from AST
3
+ */
4
+ export interface RouteInfo {
5
+ method: string;
6
+ path: string;
7
+ handlerName?: string;
8
+ handlerSource?: string;
9
+ requestTypes?: {
10
+ body?: any;
11
+ query?: Record<string, string>;
12
+ params?: Record<string, string>;
13
+ headers?: Record<string, string>;
14
+ };
15
+ responseType?: string;
16
+ responseSchema?: any;
17
+ summary?: string;
18
+ description?: string;
19
+ tags?: string[];
20
+ operationId?: string;
21
+ emits?: {
22
+ event: string;
23
+ payload?: any;
24
+ location?: {
25
+ startLine: number;
26
+ endLine: number;
27
+ };
28
+ }[];
29
+ sourceContext?: {
30
+ file: string;
31
+ startLine: number;
32
+ endLine: number;
33
+ highlights?: {
34
+ startLine: number;
35
+ endLine: number;
36
+ type: 'emit' | 'return-success' | 'return-warning';
37
+ }[];
38
+ };
39
+ }
40
+ /**
41
+ * Dependency information
42
+ */
43
+ interface DependencyInfo {
44
+ packageName: string;
45
+ version?: string;
46
+ importPath: string;
47
+ isExternal: boolean;
48
+ }
49
+ /**
50
+ * Application/Router instance found in code
51
+ */
52
+ export interface ApplicationInstance {
53
+ name: string;
54
+ filePath: string;
55
+ className: 'Shokupan' | 'ShokupanRouter' | 'Controller';
56
+ controllerPrefix?: string;
57
+ routes: RouteInfo[];
58
+ mounted: MountInfo[];
59
+ }
60
+ interface MountInfo {
61
+ prefix: string;
62
+ target: string;
63
+ targetFilePath?: string;
64
+ dependency?: DependencyInfo;
65
+ sourceContext?: {
66
+ file: string;
67
+ startLine: number;
68
+ endLine: number;
69
+ };
70
+ }
71
+ /**
72
+ * Main analyzer class
73
+ */
74
+ export declare class OpenAPIAnalyzer {
75
+ private rootDir;
76
+ private files;
77
+ private applications;
78
+ private program?;
79
+ private entrypoint?;
80
+ constructor(rootDir: string, entrypoint?: string);
81
+ /**
82
+ * Main analysis entry point
83
+ */
84
+ /**
85
+ * Main analysis entry point
86
+ */
87
+ analyze(): Promise<{
88
+ applications: ApplicationInstance[];
89
+ }>;
90
+ /**
91
+ * Remove GenericModules that are not mounted by any Shokupan application/router
92
+ */
93
+ private pruneApplications;
94
+ /**
95
+ * Recursively scan directory for TypeScript/JavaScript files
96
+ */
97
+ private scanDirectory;
98
+ /**
99
+ * Process source maps to reconstruct TypeScript
100
+ */
101
+ private processSourceMaps;
102
+ /**
103
+ * Parse TypeScript files and create AST
104
+ */
105
+ private parseTypeScriptFiles;
106
+ /**
107
+ * Find all Shokupan/ShokupanRouter instances
108
+ */
109
+ private findApplications;
110
+ /**
111
+ * Visit AST node to find application instances
112
+ */
113
+ private visitNode;
114
+ /**
115
+ * Extract route information from applications
116
+ */
117
+ private extractRoutes;
118
+ /**
119
+ * Extract routes from a Controller class
120
+ */
121
+ private extractRoutesFromController;
122
+ /**
123
+ * Extract routes from a specific file
124
+ */
125
+ private extractRoutesFromFile;
126
+ /**
127
+ * Extract route information from a route call (e.g., app.get('/path', handler))
128
+ */
129
+ private extractRouteFromCall;
130
+ /**
131
+ * Analyze a route handler to extract type information
132
+ */
133
+ private analyzeHandler;
134
+ /**
135
+ * Convert an Expression node to an OpenAPI schema (best effort)
136
+ */
137
+ private convertExpressionToSchema;
138
+ /**
139
+ * Check if an expression is a call to ctx.body()
140
+ */
141
+ private isCtxBodyCall;
142
+ /**
143
+ * Convert a TypeScript TypeNode to an OpenAPI schema
144
+ */
145
+ private convertTypeNodeToSchema;
146
+ /**
147
+ * Extract mount information from mount call
148
+ */
149
+ private extractMountFromCall;
150
+ /**
151
+ * Check if a reference is to an external dependency
152
+ */
153
+ private checkIfExternalDependency;
154
+ /**
155
+ * Get package version from package.json
156
+ */
157
+ private getPackageVersion;
158
+ /**
159
+ * Generate OpenAPI specification
160
+ */
161
+ generateOpenAPISpec(): any;
162
+ }
163
+ /**
164
+ * Analyze a directory and generate OpenAPI spec
165
+ */
166
+ export declare function analyzeDirectory(directory: string): Promise<any>;
167
+ export {};
@@ -21,6 +21,11 @@ export type ScalarPluginOptions = {
21
21
  * Only works with TypeScript entrypoints.
22
22
  */
23
23
  enableStaticAnalysis?: boolean;
24
+ /**
25
+ * Path to mount the plugin to.
26
+ * @default '/reference'
27
+ */
28
+ path?: string;
24
29
  };
25
30
  /**
26
31
  * Scalar plugin. This plugin provides an API reference interface for your API.
@@ -29,8 +34,10 @@ export type ScalarPluginOptions = {
29
34
  */
30
35
  export declare class ScalarPlugin extends ShokupanRouter<any> implements ShokupanPlugin {
31
36
  private readonly pluginOptions;
37
+ private eta;
32
38
  constructor(pluginOptions?: ScalarPluginOptions);
33
- onInit(app: Shokupan, options?: ShokupanPluginOptions): void;
34
- private init;
39
+ onInit(app: Shokupan, options?: ShokupanPluginOptions): Promise<void>;
40
+ private ensureEta;
41
+ private initRoutes;
35
42
  onMount(parent: ShokupanRouter<any>): void;
36
43
  }
@@ -0,0 +1,14 @@
1
+ import { Server } from 'socket.io';
2
+ import { Shokupan } from '../../shokupan';
3
+ /**
4
+ * Attaches the Shokupan HTTP Bridge and Event System to a Socket.IO server.
5
+ * This makes the Shokupan HTTP APIs accessible via Socket.IO events.
6
+ *
7
+ * Send events as `shokupan:request` events with the payload { type: "http", id: "123", body: {} }.
8
+ *
9
+ * Responses are emitted as `shokupan:response` events with the payload { id, status, body }
10
+ *
11
+ * @param io The Socket.IO server instance
12
+ * @param app The Shokupan application instance
13
+ */
14
+ export declare function attachSocketIOBridge(io: Server, app: Shokupan): void;
package/dist/router.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { ShokupanContext } from './context';
2
2
  import { Shokupan } from './shokupan';
3
+ import { SurrealDatastore } from './util/datastore';
3
4
  import { $appRoot, $childControllers, $childRouters, $isApplication, $isMounted, $isRouter, $mountPath, $parent, $routes } from './util/symbol';
4
5
  import { GuardAPISpec, HeadersInit, JSXRenderer, Method, MethodAPISpec, Middleware, OpenAPIOptions, ProcessResult, RequestOptions, RouteMetadata, RouteParams, ShokupanController, ShokupanHandler, ShokupanHooks, ShokupanRoute, ShokupanRouteConfig, StaticServeOptions } from './util/types';
5
6
  export declare const RouterRegistry: Map<string, ShokupanRouter<any>>;
@@ -73,69 +74,92 @@ export declare class ShokupanRouter<T extends Record<string, any> = Record<strin
73
74
  private [$parent];
74
75
  [$childRouters]: ShokupanRouter<T>[];
75
76
  [$childControllers]: ShokupanController[];
77
+ get db(): SurrealDatastore | undefined;
76
78
  private hookCache;
77
79
  private hooksInitialized;
78
80
  middleware: Middleware[];
79
- get rootConfig(): {
80
- [x: string]: any;
81
- port?: number;
82
- hostname?: string;
83
- development?: boolean;
84
- enableAsyncLocalStorage?: boolean;
85
- enableOpenApiGen?: boolean;
86
- reusePort?: boolean;
87
- controllersOnly?: boolean;
81
+ get rootConfig(): Partial<{
82
+ [key: string]: any;
83
+ port: number;
84
+ hostname: string;
85
+ development: boolean;
86
+ enableAsyncLocalStorage: boolean;
87
+ enableOpenApiGen: boolean;
88
+ enableAsyncApiGen: boolean;
89
+ reusePort: boolean;
90
+ controllersOnly: boolean;
88
91
  enableTracing?: boolean;
89
92
  jsonParser?: "native" | "parse-json" | "secure-json-parse";
90
93
  autoBackpressureFeedback?: boolean;
91
94
  autoBackpressureLevel?: number;
92
- enableMiddlewareTracking?: boolean;
95
+ enableMiddlewareTracking: boolean;
93
96
  middlewareTrackingMaxCapacity?: number;
97
+ enableHTTPBridge?: boolean;
98
+ websocketErrorHandler?: (err: any, ctx: ShokupanContext<Record<string, any>, Record<string, string>>) => void | Promise<void>;
99
+ idGenerator?: () => string;
94
100
  middlewareTrackingTTL?: number;
95
- httpLogger?: (ctx: ShokupanContext<Record<string, any>, Record<string, string>>) => void;
96
- logger?: {
97
- verbose?: boolean;
98
- info?: (msg: string, props: Record<string, any>) => void;
99
- debug?: (msg: string, props: Record<string, any>) => void;
100
- warning?: (msg: string, props: Record<string, any>) => void;
101
- error?: (msg: string, props: Record<string, any>) => void;
102
- fatal?: (msg: string, props: Record<string, any>) => void;
101
+ httpLogger: (ctx: ShokupanContext<Record<string, any>, Record<string, string>>) => void;
102
+ logger: {
103
+ verbose: boolean;
104
+ info: (msg: string, props: Record<string, any>) => void;
105
+ debug: (msg: string, props: Record<string, any>) => void;
106
+ warning: (msg: string, props: Record<string, any>) => void;
107
+ error: (msg: string, props: Record<string, any>) => void;
108
+ fatal: (msg: string, props: Record<string, any>) => void;
103
109
  };
104
- readTimeout?: number;
105
- requestTimeout?: number;
106
- writeTimeout?: number;
107
- renderer?: JSXRenderer;
108
- serverFactory?: import('.').ServerFactory;
109
- hooks?: {
110
- onError?: (ctx: ShokupanContext<Record<string, any>, Record<string, string>>, error: unknown) => void | Promise<void>;
111
- onRequestStart?: (ctx: ShokupanContext<Record<string, any>, Record<string, string>>) => void | Promise<void>;
112
- onRequestEnd?: (ctx: ShokupanContext<Record<string, any>, Record<string, string>>) => void | Promise<void>;
113
- onResponseStart?: (ctx: ShokupanContext<Record<string, any>, Record<string, string>>, response: Response) => void | Promise<void>;
114
- onResponseEnd?: (ctx: ShokupanContext<Record<string, any>, Record<string, string>>, response: Response) => void | Promise<void>;
115
- beforeValidate?: (ctx: ShokupanContext<Record<string, any>, Record<string, string>>, data: any) => void | Promise<void>;
116
- afterValidate?: (ctx: ShokupanContext<Record<string, any>, Record<string, string>>, data: any) => void | Promise<void>;
117
- onReadTimeout?: (ctx: ShokupanContext<Record<string, any>, Record<string, string>>) => void | Promise<void>;
118
- onWriteTimeout?: (ctx: ShokupanContext<Record<string, any>, Record<string, string>>) => void | Promise<void>;
119
- onRequestTimeout?: (ctx: ShokupanContext<Record<string, any>, Record<string, string>>) => void | Promise<void>;
120
- } | {
121
- onError?: (ctx: ShokupanContext<Record<string, any>, Record<string, string>>, error: unknown) => void | Promise<void>;
122
- onRequestStart?: (ctx: ShokupanContext<Record<string, any>, Record<string, string>>) => void | Promise<void>;
123
- onRequestEnd?: (ctx: ShokupanContext<Record<string, any>, Record<string, string>>) => void | Promise<void>;
124
- onResponseStart?: (ctx: ShokupanContext<Record<string, any>, Record<string, string>>, response: Response) => void | Promise<void>;
125
- onResponseEnd?: (ctx: ShokupanContext<Record<string, any>, Record<string, string>>, response: Response) => void | Promise<void>;
126
- beforeValidate?: (ctx: ShokupanContext<Record<string, any>, Record<string, string>>, data: any) => void | Promise<void>;
127
- afterValidate?: (ctx: ShokupanContext<Record<string, any>, Record<string, string>>, data: any) => void | Promise<void>;
128
- onReadTimeout?: (ctx: ShokupanContext<Record<string, any>, Record<string, string>>) => void | Promise<void>;
129
- onWriteTimeout?: (ctx: ShokupanContext<Record<string, any>, Record<string, string>>) => void | Promise<void>;
130
- onRequestTimeout?: (ctx: ShokupanContext<Record<string, any>, Record<string, string>>) => void | Promise<void>;
131
- }[];
132
- validateStatusCodes?: boolean;
133
- };
110
+ readTimeout: number;
111
+ requestTimeout: number;
112
+ writeTimeout: number;
113
+ renderer: JSXRenderer;
114
+ serverFactory: import('.').ServerFactory;
115
+ hooks: ShokupanHooks<Record<string, any>> | ShokupanHooks<Record<string, any>>[];
116
+ validateStatusCodes: boolean;
117
+ surreal?: {
118
+ engines?: import('surrealdb').Engines;
119
+ url?: string;
120
+ connectOptions?: import('surrealdb').ConnectOptions;
121
+ namespace?: string;
122
+ database?: string;
123
+ };
124
+ aiPlugin?: {
125
+ enabled?: boolean;
126
+ name_for_human?: string;
127
+ name_for_model?: string;
128
+ description_for_human?: string;
129
+ description_for_model?: string;
130
+ auth?: {
131
+ type: "none" | "service_http" | "user_http" | "oauth";
132
+ [key: string]: any;
133
+ };
134
+ api?: {
135
+ type: "openapi";
136
+ url?: string;
137
+ is_user_authenticated?: boolean;
138
+ };
139
+ logo_url?: string;
140
+ contact_email?: string;
141
+ legal_info_url?: string;
142
+ };
143
+ apiCatalog?: {
144
+ enabled?: boolean;
145
+ versions?: Array<{
146
+ name: string;
147
+ url: string;
148
+ spec_url: string;
149
+ }>;
150
+ };
151
+ }>;
134
152
  get root(): Shokupan<any>;
135
153
  [$routes]: ShokupanRoute[];
136
154
  private trie;
137
155
  metadata?: RouteMetadata;
138
156
  private currentGuards;
157
+ private eventHandlers;
158
+ /**
159
+ * Registers middleware for this router.
160
+ * Middleware will run for all routes matched by this router.
161
+ */
162
+ use(middleware: Middleware): this;
139
163
  getComponentRegistry(): {
140
164
  metadata: RouteMetadata;
141
165
  middleware: {
@@ -174,6 +198,18 @@ export declare class ShokupanRouter<T extends Record<string, any> = Record<strin
174
198
  };
175
199
  constructor(config?: ShokupanRouteConfig);
176
200
  private isRouterInstance;
201
+ /**
202
+ * Registers an event handler for WebSocket.
203
+ */
204
+ event(name: string, handler: ShokupanHandler<T>): this;
205
+ /**
206
+ * Finds an event handler(s) by name.
207
+ */
208
+ findEvent(name: string): ShokupanHandler<T>[] | null;
209
+ /**
210
+ * Returns all registered event handlers.
211
+ */
212
+ getEventHandlers(): Map<string, ShokupanHandler<T>[]>;
177
213
  /**
178
214
  * Mounts a controller instance to a path prefix.
179
215
  *
@@ -239,7 +275,7 @@ export declare class ShokupanRouter<T extends Record<string, any> = Record<strin
239
275
  * @param arg.renderer - JSX renderer for the route
240
276
  * @param arg.controller - Controller for the route
241
277
  */
242
- add({ method, path, spec, handler, regex: customRegex, group, requestTimeout, renderer, controller }: {
278
+ add({ method, path, spec, handler, regex: customRegex, group, requestTimeout, renderer, controller, metadata, middleware }: {
243
279
  method: Method;
244
280
  path: string;
245
281
  spec?: MethodAPISpec;
@@ -249,6 +285,11 @@ export declare class ShokupanRouter<T extends Record<string, any> = Record<strin
249
285
  requestTimeout?: number;
250
286
  renderer?: JSXRenderer;
251
287
  controller?: any;
288
+ metadata?: {
289
+ file: string;
290
+ line: number;
291
+ };
292
+ middleware?: Middleware[];
252
293
  }): this;
253
294
  /**
254
295
  * Adds a GET route to the router.
@@ -385,7 +426,7 @@ export declare class ShokupanRouter<T extends Record<string, any> = Record<strin
385
426
  * Generates an OpenAPI 3.1 Document by recursing through the router and its descendants.
386
427
  * Now includes runtime analysis of handler functions to infer request/response types.
387
428
  */
388
- generateApiSpec(options?: OpenAPIOptions): any;
429
+ generateApiSpec(options?: OpenAPIOptions): Promise<any>;
389
430
  private ensureHooksInitialized;
390
- runHooks(name: keyof ShokupanHooks, ...args: any[]): Promise<void>;
431
+ runHooks(name: keyof ShokupanHooks, ...args: any[]): void | Promise<void[]>;
391
432
  }
@@ -2,6 +2,7 @@ import { $dispatch } from './util/symbol';
2
2
  import { Middleware, ProcessResult, RequestOptions, ShokupanConfig, ShokupanPlugin } from './util/types';
3
3
  import { Server } from 'bun';
4
4
  import { ShokupanRouter } from './router';
5
+ import { SurrealDatastore } from './util/datastore';
5
6
  import { ShokupanRequest } from './util/request';
6
7
  /**
7
8
  * Shokupan Application
@@ -70,17 +71,23 @@ import { ShokupanRequest } from './util/request';
70
71
  export declare class Shokupan<T = any> extends ShokupanRouter<T> {
71
72
  readonly applicationConfig: ShokupanConfig;
72
73
  openApiSpec?: any;
74
+ asyncApiSpec?: any;
73
75
  private composedMiddleware?;
74
76
  private cpuMonitor?;
77
+ private server?;
78
+ private datastore?;
79
+ dbPromise?: Promise<any>;
80
+ get db(): SurrealDatastore | undefined;
75
81
  get logger(): {
76
- verbose?: boolean;
77
- info?: (msg: string, props: Record<string, any>) => void;
78
- debug?: (msg: string, props: Record<string, any>) => void;
79
- warning?: (msg: string, props: Record<string, any>) => void;
80
- error?: (msg: string, props: Record<string, any>) => void;
81
- fatal?: (msg: string, props: Record<string, any>) => void;
82
+ verbose: boolean;
83
+ info: (msg: string, props: Record<string, any>) => void;
84
+ debug: (msg: string, props: Record<string, any>) => void;
85
+ warning: (msg: string, props: Record<string, any>) => void;
86
+ error: (msg: string, props: Record<string, any>) => void;
87
+ fatal: (msg: string, props: Record<string, any>) => void;
82
88
  };
83
89
  constructor(applicationConfig?: ShokupanConfig);
90
+ private initDatastore;
84
91
  /**
85
92
  * Adds middleware to the application.
86
93
  */
@@ -108,7 +115,26 @@ export declare class Shokupan<T = any> extends ShokupanRouter<T> {
108
115
  * @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.
109
116
  * @returns The server instance.
110
117
  */
111
- listen(port?: number): Promise<Server | import('http').Server<typeof import('http').IncomingMessage, typeof import('http').ServerResponse>>;
118
+ listen(port?: number): Promise<Server<any>>;
119
+ /**
120
+ * Stops the application server.
121
+ *
122
+ * This method gracefully shuts down the server and stops any running monitors.
123
+ * Works transparently in both Bun and Node.js runtimes.
124
+ *
125
+ * @returns A promise that resolves when the server has been stopped.
126
+ *
127
+ * @example
128
+ * ```typescript
129
+ * const app = new Shokupan();
130
+ * const server = await app.listen(3000);
131
+ *
132
+ * // Later, when you want to stop the server
133
+ * await app.stop();
134
+ * ```
135
+ * @param closeActiveConnections — Immediately terminate in-flight requests, websockets, and stop accepting new connections.
136
+ */
137
+ stop(closeActiveConnections?: boolean): Promise<void>;
112
138
  [$dispatch](req: ShokupanRequest<T>): Promise<Response>;
113
139
  /**
114
140
  * Processes a request by wrapping the standard fetch method.
@@ -122,6 +148,6 @@ export declare class Shokupan<T = any> extends ShokupanRouter<T> {
122
148
  * @param server - The server instance.
123
149
  * @returns The response to send.
124
150
  */
125
- fetch(req: Request, server?: Server): Promise<Response>;
151
+ fetch(req: Request, server?: Server<any>): Promise<Response>;
126
152
  private handleRequest;
127
153
  }
@@ -1,6 +1,71 @@
1
- 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>;
5
- readonly ready: Promise<any>;
6
- };
1
+ import { RecordId, Surreal, RecordIdRange, Table } from 'surrealdb';
2
+ export declare class SurrealDatastore {
3
+ private readonly db;
4
+ constructor(db: Surreal);
5
+ createSchema(): void;
6
+ /**
7
+ * Select a record or contents of a table by its ID.
8
+ */
9
+ select<T = unknown>(id: RecordId | RecordIdRange | Table): Promise<(T extends object ? T extends {
10
+ id: infer Id;
11
+ } ? Id extends RecordId<string, import('surrealdb').RecordIdValue> ? T : Id extends import('surrealdb').RecordIdValue ? {
12
+ id: RecordId<string, Id>;
13
+ } & Omit<T, "id"> : {
14
+ id: RecordId;
15
+ } & Omit<T, "id"> : {
16
+ id: RecordId;
17
+ } & T : {
18
+ id: RecordId;
19
+ }) extends infer T_1 ? { [K in keyof T_1]: T_1[K]; } : never>;
20
+ /**
21
+ * Merge update data into a record by its ID.
22
+ */
23
+ merge<T extends Record<string, any>>(id: RecordId, data: T): Promise<(T extends object ? T extends {
24
+ id: infer Id;
25
+ } ? Id extends RecordId<string, import('surrealdb').RecordIdValue> ? T : Id extends import('surrealdb').RecordIdValue ? {
26
+ id: RecordId<string, Id>;
27
+ } & Omit<T, "id"> : {
28
+ id: RecordId;
29
+ } & Omit<T, "id"> : {
30
+ id: RecordId;
31
+ } & T : {
32
+ id: RecordId;
33
+ }) extends infer T_1 ? { [K in keyof T_1]: T_1[K]; } : never>;
34
+ /**
35
+ * Create a record by its ID.
36
+ */
37
+ create<T extends Record<string, any>>(id: RecordId, data: Omit<T, 'id'>): Promise<{
38
+ id: RecordId;
39
+ }>;
40
+ /**
41
+ * Upsert a record by its ID.
42
+ */
43
+ upsert<T extends Record<string, any>>(id: RecordId, data: T): Promise<(T extends object ? T extends {
44
+ id: infer Id;
45
+ } ? Id extends RecordId<string, import('surrealdb').RecordIdValue> ? T : Id extends import('surrealdb').RecordIdValue ? {
46
+ id: RecordId<string, Id>;
47
+ } & Omit<T, "id"> : {
48
+ id: RecordId;
49
+ } & Omit<T, "id"> : {
50
+ id: RecordId;
51
+ } & T : {
52
+ id: RecordId;
53
+ }) extends infer T_1 ? { [K in keyof T_1]: T_1[K]; } : never>;
54
+ /**
55
+ * Delete a record by its ID.
56
+ */
57
+ delete(id: RecordId): Promise<{
58
+ id: RecordId;
59
+ }>;
60
+ /**
61
+ * Run a SurrealDB query.
62
+ */
63
+ query<T extends Array<unknown>>(query: string, vars?: Record<string, any>): Promise<T extends [] ? unknown[] : { [K in keyof T]: T[K]; }>;
64
+ /**
65
+ * Create a relationship between two records.
66
+ */
67
+ relate(fromId: any, edgeId: any, toId: any, data?: Record<string, any>): Promise<{
68
+ [x: string]: /*elided*/ any;
69
+ }>;
70
+ disconnect(): Promise<true>;
71
+ }
@@ -1,5 +1,5 @@
1
1
  import { RateLimitOptions } from '../plugins/middleware/rate-limit';
2
- import { GuardAPISpec, MethodAPISpec, Middleware } from './types';
2
+ import { AsyncAPISpec, GuardAPISpec, MethodAPISpec, Middleware } from './types';
3
3
  /**
4
4
  * Class Decorator: Defines the base path for a controller.
5
5
  */
@@ -35,7 +35,7 @@ export declare const Ctx: (name?: string) => (target: any, propertyKey: string,
35
35
  /**
36
36
  * Decorator: Overrides the OpenAPI specification for a route.
37
37
  */
38
- export declare function Spec(spec: MethodAPISpec | GuardAPISpec): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => void;
38
+ export declare function Spec(spec: MethodAPISpec | GuardAPISpec | AsyncAPISpec): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => void;
39
39
  /**
40
40
  * Decorator: Binds a method to the GET HTTP verb.
41
41
  */
@@ -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
+ }
@@ -1,2 +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
+ };
1
31
  export declare const VALID_HTTP_STATUSES: Set<number>;
2
32
  export declare const VALID_REDIRECT_STATUSES: Set<number>;
@@ -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
  /**