@spikard/node 0.11.0 → 0.13.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/README.md CHANGED
@@ -1,18 +1,37 @@
1
- # Spikard for Node.js
1
+ <!-- GENERATED FILE — DO NOT EDIT DIRECTLY. Run: task readme:generate -->
2
2
 
3
- [![Documentation](https://img.shields.io/badge/docs-spikard.dev-blue)](https://spikard.dev)
4
- [![Crates.io](https://img.shields.io/crates/v/spikard.svg?color=blue)](https://crates.io/crates/spikard)
5
- [![PyPI](https://img.shields.io/pypi/v/spikard.svg?color=blue)](https://pypi.org/project/spikard/)
6
- [![npm](https://img.shields.io/npm/v/@spikard/node.svg?color=blue)](https://www.npmjs.com/package/@spikard/node)
7
- [![Gem](https://img.shields.io/gem/v/spikard.svg?color=blue)](https://rubygems.org/gems/spikard)
8
- [![Packagist](https://img.shields.io/packagist/v/spikard/spikard.svg?color=blue)](https://packagist.org/packages/spikard/spikard)
9
- [![Hex.pm](https://img.shields.io/hexpm/v/spikard.svg?color=blue)](https://hex.pm/packages/spikard)
10
- [![License](https://img.shields.io/badge/license-MIT-blue.svg)](../../LICENSE)
3
+ # Spikard for Node.js
11
4
 
12
- High-performance HTTP framework for Node.js powered by a Rust core. Provides type-safe routing, validation, middleware, and testing via **napi-rs** bindings with zero-copy JSON conversion.
5
+ <div align="center" style="display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; margin: 20px 0;">
6
+ <a href="https://spikard.dev">
7
+ <img src="https://img.shields.io/badge/docs-spikard.dev-007ec6" alt="Documentation">
8
+ </a>
9
+ <a href="https://crates.io/crates/spikard">
10
+ <img src="https://img.shields.io/crates/v/spikard.svg?color=007ec6" alt="Crates.io">
11
+ </a>
12
+ <a href="https://pypi.org/project/spikard/">
13
+ <img src="https://img.shields.io/pypi/v/spikard.svg?color=007ec6" alt="PyPI">
14
+ </a>
15
+ <a href="https://www.npmjs.com/package/@spikard/node">
16
+ <img src="https://img.shields.io/npm/v/@spikard/node.svg?color=007ec6" alt="npm">
17
+ </a>
18
+ <a href="https://rubygems.org/gems/spikard">
19
+ <img src="https://img.shields.io/gem/v/spikard.svg?color=007ec6" alt="RubyGems">
20
+ </a>
21
+ <a href="https://packagist.org/packages/spikard/spikard">
22
+ <img src="https://img.shields.io/packagist/v/spikard/spikard.svg?color=007ec6" alt="Packagist">
23
+ </a>
24
+ <a href="https://hex.pm/packages/spikard">
25
+ <img src="https://img.shields.io/hexpm/v/spikard.svg?color=007ec6" alt="Hex.pm">
26
+ </a>
27
+ <a href="https://github.com/Goldziher/spikard/blob/main/LICENSE">
28
+ <img src="https://img.shields.io/badge/license-MIT-007ec6" alt="License">
29
+ </a>
30
+ </div>
31
+
32
+ High-performance HTTP framework for Node.js powered by a Rust core. Provides type-safe routing, validation, middleware, and testing via napi-rs bindings with zero-copy JSON conversion.
13
33
 
14
34
  ## Features
15
-
16
35
  - **Rust-Powered Performance**: Native speed via Tokio with dedicated thread pool
17
36
  - **Full TypeScript Support**: Auto-generated types from napi-rs FFI bindings
18
37
  - **Zero-Copy JSON**: Direct conversion without serialization overhead
@@ -77,7 +96,6 @@ app.addRoute(
77
96
 
78
97
  app.run({ port: 8000 });
79
98
  ```
80
-
81
99
  ## Routing & Schemas
82
100
 
83
101
  Routes support Zod validation (recommended) or raw JSON Schema:
@@ -215,6 +233,28 @@ app.onResponse(async (response) => {
215
233
  });
216
234
  ```
217
235
 
236
+ ## Performance
237
+
238
+ Benchmarked across 34 workloads at 100 concurrency ([methodology](../../docs/benchmarks/methodology.md)):
239
+
240
+ | Framework | Avg RPS | P50 (ms) | P99 (ms) |
241
+ |-----------|--------:|----------:|----------:|
242
+ | **spikard (Bun)** | 49,460 | 2.18 | 4.21 |
243
+ | **spikard (Node)** | 46,160 | 2.18 | 3.35 |
244
+ | elysia | 44,326 | 2.41 | 4.68 |
245
+ | kito | 36,958 | 4.94 | 12.86 |
246
+ | fastify | 19,167 | 6.74 | 14.76 |
247
+ | morojs | 14,196 | 6.44 | 12.61 |
248
+ | hono | 10,928 | 10.91 | 18.62 |
249
+
250
+ Spikard is **1.2x faster than Kito and 2.4x faster than Fastify**.
251
+
252
+ Key optimizations:
253
+ - **napi-rs** zero-copy FFI bindings
254
+ - **Dedicated Tokio runtime** without blocking Node event loop
255
+ - **Zero-copy JSON** conversion (30-40% faster than JSON.parse)
256
+ - **ThreadsafeFunction** for async JavaScript callbacks
257
+
218
258
  ## Testing
219
259
 
220
260
  Use TestClient for HTTP, WebSocket, and SSE testing:
@@ -237,48 +277,22 @@ await ws.sendJson({ message: "hello" });
237
277
  const sse = await client.get("/events");
238
278
  ```
239
279
 
240
- ## Performance
241
-
242
- Benchmarked across 34 workloads at 100 concurrency ([methodology](../../docs/benchmarks/methodology.md)):
243
-
244
- | Framework | Avg RPS | P50 (ms) | P99 (ms) |
245
- |-----------|--------:|----------:|----------:|
246
- | **spikard (Bun)** | 49,460 | 2.18 | 4.21 |
247
- | **spikard (Node)** | 46,160 | 2.18 | 3.35 |
248
- | elysia | 44,326 | 2.41 | 4.68 |
249
- | kito | 36,958 | 4.94 | 12.86 |
250
- | fastify | 19,167 | 6.74 | 14.76 |
251
- | morojs | 14,196 | 6.44 | 12.61 |
252
- | hono | 10,928 | 10.91 | 18.62 |
253
-
254
- Spikard Node is **1.2x faster** than Kito and **2.4x faster** than Fastify.
255
-
256
- Key optimizations:
257
- - **napi-rs** zero-copy FFI bindings
258
- - **Dedicated Tokio runtime** without blocking Node event loop
259
- - **Zero-copy JSON** conversion (30-40% faster than JSON.parse)
260
- - **ThreadsafeFunction** for async JavaScript callbacks
261
-
262
280
  ## Examples
263
281
 
264
- See [examples/](../../examples/) for runnable projects. Code generation is supported for OpenAPI, GraphQL, AsyncAPI, and JSON-RPC specifications.
282
+ See [examples/](../../examples/) for runnable projects. Code generation is supported for OpenAPI, GraphQL, AsyncAPI, OpenRPC/JSON-RPC, and Protobuf/gRPC specifications.
265
283
 
266
284
  ## Documentation
267
285
 
268
286
  Full documentation at [spikard.dev](https://spikard.dev). See also [CONTRIBUTING.md](../../CONTRIBUTING.md).
269
287
 
270
- ## Ecosystem
271
-
272
- Spikard is available across multiple languages:
288
+ ## Other Languages
273
289
 
274
- | Platform | Package | Status |
275
- |----------|---------|--------|
276
- | **Node.js** | [@spikard/node](https://www.npmjs.com/package/@spikard/node) | Stable |
277
- | **Python** | [spikard](https://pypi.org/project/spikard/) | Stable |
278
- | **Rust** | [spikard](https://crates.io/crates/spikard) | Stable |
279
- | **Ruby** | [spikard](https://rubygems.org/gems/spikard) | Stable |
280
- | **PHP** | [spikard/spikard](https://packagist.org/packages/spikard/spikard) | Stable |
281
- | **Elixir** | [spikard](https://hex.pm/packages/spikard) | Stable |
290
+ - **Rust:** [Crates.io](https://crates.io/crates/spikard)
291
+ - **Python:** [PyPI](https://pypi.org/project/spikard/)
292
+ - **TypeScript:** [npm (@spikard/node)](https://www.npmjs.com/package/@spikard/node)
293
+ - **Ruby:** [RubyGems](https://rubygems.org/gems/spikard)
294
+ - **PHP:** [Packagist](https://packagist.org/packages/spikard/spikard)
295
+ - **Elixir:** [Hex.pm](https://hex.pm/packages/spikard)
282
296
 
283
297
  ## License
284
298
 
package/dist/index.d.mts CHANGED
@@ -1,67 +1,3 @@
1
- interface StreamingResponseInit {
2
- statusCode?: number;
3
- headers?: Record<string, string>;
4
- }
5
- declare const STREAM_HANDLE_PROP: "__spikard_stream_handle";
6
- type StreamChunk = JsonValue | string | Buffer | Uint8Array | ArrayBuffer | ArrayBufferView | null | undefined;
7
- type ChunkIterator = AsyncIterator<StreamChunk> & AsyncIterable<StreamChunk>;
8
- type StreamingHandle = {
9
- kind: "native";
10
- handle: number;
11
- init: StreamingResponseInit;
12
- } | {
13
- kind: "js";
14
- iterator: ChunkIterator;
15
- init: StreamingResponseInit;
16
- };
17
- declare class StreamingResponse {
18
- readonly [STREAM_HANDLE_PROP]: StreamingHandle;
19
- constructor(stream: AsyncIterable<StreamChunk> | AsyncIterator<StreamChunk>, init?: StreamingResponseInit);
20
- }
21
-
22
- type JsonPrimitive = string | number | boolean | null;
23
- type JsonValue = JsonPrimitive | JsonValue[] | {
24
- [Key in string]: JsonValue;
25
- };
26
- type JsonRecord = Record<string, JsonValue>;
27
- type MaybePromise<T> = T | Promise<T>;
28
- interface Base64EncodedBody {
29
- __spikard_base64__: string;
30
- }
31
- type HandlerBody = JsonValue | Base64EncodedBody | null;
32
- interface StructuredHandlerResponse {
33
- status?: number;
34
- statusCode?: number;
35
- headers?: Record<string, string>;
36
- body?: HandlerBody;
37
- }
38
- type HandlerResult = StructuredHandlerResponse | JsonValue | StreamingResponse | undefined;
39
- type HandlerFunction<TReturn extends HandlerResult = HandlerResult> = (request: Request) => MaybePromise<TReturn>;
40
- type NativeHandlerFunction<TReturn extends HandlerResult = HandlerResult> = (requestJson: string) => MaybePromise<TReturn | string>;
41
- type WebSocketHandler = (message: unknown) => MaybePromise<unknown>;
42
- interface WebSocketOptions {
43
- onConnect?: () => MaybePromise<void>;
44
- onDisconnect?: () => MaybePromise<void>;
45
- messageSchema?: unknown;
46
- responseSchema?: unknown;
47
- handlerName?: string;
48
- }
49
-
50
- interface Request {
51
- method: string;
52
- path: string;
53
- params: Record<string, string>;
54
- pathParams: Record<string, string>;
55
- query: Record<string, string>;
56
- queryParams: Record<string, string>;
57
- headers: Record<string, string>;
58
- cookies: Record<string, string>;
59
- body: Buffer | null;
60
- dependencies: Record<string, unknown> | undefined;
61
- json<T = JsonValue>(): T;
62
- form(): Record<string, string>;
63
- }
64
-
65
1
  interface CompressionConfig {
66
2
  gzip?: boolean;
67
3
  brotli?: boolean;
@@ -117,6 +53,12 @@ interface OpenApiConfig {
117
53
  servers?: ServerInfo[];
118
54
  securitySchemes?: Record<string, SecuritySchemeInfo>;
119
55
  }
56
+ interface JsonRpcConfig {
57
+ enabled?: boolean;
58
+ endpointPath?: string;
59
+ enableBatch?: boolean;
60
+ maxBatchSize?: number;
61
+ }
120
62
  interface StaticFilesConfig {
121
63
  directory: string;
122
64
  routePrefix: string;
@@ -138,62 +80,7 @@ interface ServerConfig {
138
80
  gracefulShutdown?: boolean;
139
81
  shutdownTimeout?: number;
140
82
  openapi?: OpenApiConfig | null;
141
- }
142
-
143
- interface ServerOptions {
144
- host?: string;
145
- port?: number;
146
- }
147
- declare function runServer(app: SpikardApp, config?: ServerConfig | ServerOptions): void;
148
-
149
- type DependencyValue = unknown;
150
- type DependencyFactory = (dependencies: Record<string, DependencyValue>) => MaybePromise<DependencyValue>;
151
- interface DependencyOptions {
152
- dependsOn?: string[];
153
- singleton?: boolean;
154
- cacheable?: boolean;
155
- }
156
- interface DependencyDescriptor {
157
- isFactory: boolean;
158
- value?: DependencyValue | undefined;
159
- factory?: DependencyFactory | undefined;
160
- dependsOn: string[];
161
- singleton: boolean;
162
- cacheable: boolean;
163
- }
164
- type LifecycleHookPayload = Request | StructuredHandlerResponse;
165
- type LifecycleHookFunction = (payload: LifecycleHookPayload) => MaybePromise<LifecycleHookPayload>;
166
- interface LifecycleHooks {
167
- onRequest: LifecycleHookFunction[];
168
- preValidation: LifecycleHookFunction[];
169
- preHandler: LifecycleHookFunction[];
170
- onResponse: LifecycleHookFunction[];
171
- onError: LifecycleHookFunction[];
172
- }
173
- declare class Spikard implements SpikardApp {
174
- routes: RouteMetadata[];
175
- handlers: Record<string, HandlerFunction | NativeHandlerFunction>;
176
- websocketRoutes: RouteMetadata[];
177
- websocketHandlers: Record<string, Record<string, unknown>>;
178
- lifecycleHooks: LifecycleHooks;
179
- dependencies: Record<string, DependencyDescriptor>;
180
- addRoute(metadata: RouteMetadata, handler: HandlerFunction | NativeHandlerFunction): void;
181
- websocket(path: string, handler: WebSocketHandler, options?: WebSocketOptions): void;
182
- run(options?: ServerOptions): void;
183
- onRequest(hook: LifecycleHookFunction): LifecycleHookFunction;
184
- preValidation(hook: LifecycleHookFunction): LifecycleHookFunction;
185
- preHandler(hook: LifecycleHookFunction): LifecycleHookFunction;
186
- onResponse(hook: LifecycleHookFunction): LifecycleHookFunction;
187
- onError(hook: LifecycleHookFunction): LifecycleHookFunction;
188
- provide(key: string, valueOrFactory: DependencyValue | DependencyFactory, options?: DependencyOptions): this;
189
- getLifecycleHooks(): LifecycleHooks;
190
- }
191
-
192
- declare function run(work: () => void | Promise<void>): void;
193
-
194
- declare const background_run: typeof run;
195
- declare namespace background {
196
- export { background_run as run };
83
+ jsonrpc?: JsonRpcConfig | null;
197
84
  }
198
85
 
199
86
  type GrpcMetadata = Record<string, string>;
@@ -207,9 +94,37 @@ interface GrpcResponse {
207
94
  payload: Buffer;
208
95
  metadata?: GrpcMetadata;
209
96
  }
97
+ interface GrpcClientStreamRequest {
98
+ serviceName: string;
99
+ methodName: string;
100
+ metadata: GrpcMetadata;
101
+ messages: Buffer[];
102
+ }
103
+ interface GrpcServerStreamResponse {
104
+ messages: Buffer[];
105
+ }
106
+ interface GrpcBidiStreamRequest {
107
+ serviceName: string;
108
+ methodName: string;
109
+ metadata: GrpcMetadata;
110
+ messages: Buffer[];
111
+ }
112
+ interface GrpcBidiStreamResponse {
113
+ messages: Buffer[];
114
+ metadata?: GrpcMetadata;
115
+ }
210
116
  interface GrpcHandler {
211
117
  handleRequest(request: GrpcRequest): Promise<GrpcResponse>;
212
118
  }
119
+ interface GrpcServerStreamingHandler {
120
+ handleServerStream(request: GrpcRequest): Promise<GrpcServerStreamResponse>;
121
+ }
122
+ interface GrpcClientStreamingHandler {
123
+ handleClientStream(request: GrpcClientStreamRequest): Promise<GrpcResponse>;
124
+ }
125
+ interface GrpcBidirectionalStreamingHandler {
126
+ handleBidiStream(request: GrpcBidiStreamRequest): Promise<GrpcBidiStreamResponse>;
127
+ }
213
128
  declare enum GrpcStatusCode {
214
129
  OK = 0,
215
130
  CANCELLED = 1,
@@ -233,9 +148,29 @@ declare class GrpcError extends Error {
233
148
  readonly code: GrpcStatusCode;
234
149
  constructor(code: GrpcStatusCode, message: string);
235
150
  }
236
- interface GrpcServiceConfig {
151
+ type GrpcRpcMode = "unary" | "serverStreaming" | "clientStreaming" | "bidirectionalStreaming";
152
+ type GrpcMethodHandler = GrpcHandler | GrpcServerStreamingHandler | GrpcClientStreamingHandler | GrpcBidirectionalStreamingHandler;
153
+ interface GrpcMethodConfig {
237
154
  serviceName: string;
238
- handler: GrpcHandler;
155
+ methodName: string;
156
+ rpcMode: GrpcRpcMode;
157
+ handler: GrpcMethodHandler;
158
+ }
159
+ declare class GrpcService {
160
+ private readonly methods;
161
+ private methodKey;
162
+ private registerMethod;
163
+ registerUnary(serviceName: string, methodName: string, handler: GrpcHandler): this;
164
+ registerServerStreaming(serviceName: string, methodName: string, handler: GrpcServerStreamingHandler): this;
165
+ registerClientStreaming(serviceName: string, methodName: string, handler: GrpcClientStreamingHandler): this;
166
+ registerBidirectionalStreaming(serviceName: string, methodName: string, handler: GrpcBidirectionalStreamingHandler): this;
167
+ unregister(serviceName: string, methodName: string): void;
168
+ getMethod(serviceName: string, methodName: string): GrpcMethodConfig | undefined;
169
+ serviceNames(): string[];
170
+ methodNames(serviceName: string): string[];
171
+ hasMethod(serviceName: string, methodName: string): boolean;
172
+ entries(): GrpcMethodConfig[];
173
+ handleRequest(request: GrpcRequest): Promise<GrpcResponse>;
239
174
  }
240
175
  type UnaryHandlerResult<TResponse> = TResponse | {
241
176
  response: TResponse;
@@ -250,6 +185,128 @@ declare function createUnaryHandler<TRequest, TResponse>(methodName: string, han
250
185
  }): GrpcHandler;
251
186
  declare function createServiceHandler(methods: Record<string, GrpcHandler>): GrpcHandler;
252
187
 
188
+ interface StreamingResponseInit {
189
+ statusCode?: number;
190
+ headers?: Record<string, string>;
191
+ }
192
+ declare const STREAM_HANDLE_PROP: "__spikard_stream_handle";
193
+ type StreamChunk = JsonValue | string | Buffer | Uint8Array | ArrayBuffer | ArrayBufferView | null | undefined;
194
+ type ChunkIterator = AsyncIterator<StreamChunk> & AsyncIterable<StreamChunk>;
195
+ type StreamingHandle = {
196
+ kind: "native";
197
+ handle: number;
198
+ init: StreamingResponseInit;
199
+ } | {
200
+ kind: "js";
201
+ iterator: ChunkIterator;
202
+ init: StreamingResponseInit;
203
+ };
204
+ declare class StreamingResponse {
205
+ readonly [STREAM_HANDLE_PROP]: StreamingHandle;
206
+ constructor(stream: AsyncIterable<StreamChunk> | AsyncIterator<StreamChunk>, init?: StreamingResponseInit);
207
+ }
208
+
209
+ type JsonPrimitive = string | number | boolean | null;
210
+ type JsonValue = JsonPrimitive | JsonValue[] | {
211
+ [Key in string]: JsonValue;
212
+ };
213
+ type JsonRecord = Record<string, JsonValue>;
214
+ type MaybePromise<T> = T | Promise<T>;
215
+ interface Base64EncodedBody {
216
+ __spikard_base64__: string;
217
+ }
218
+ type HandlerBody = JsonValue | Base64EncodedBody | null;
219
+ interface StructuredHandlerResponse {
220
+ status?: number;
221
+ statusCode?: number;
222
+ headers?: Record<string, string>;
223
+ body?: HandlerBody;
224
+ }
225
+ type HandlerResult = StructuredHandlerResponse | JsonValue | StreamingResponse | undefined;
226
+ type HandlerFunction<TReturn extends HandlerResult = HandlerResult> = (request: Request) => MaybePromise<TReturn>;
227
+ type NativeHandlerFunction<TReturn extends HandlerResult = HandlerResult> = (requestJson: string) => MaybePromise<TReturn | string>;
228
+ type WebSocketHandler = (message: unknown) => MaybePromise<unknown>;
229
+ interface WebSocketOptions {
230
+ onConnect?: () => MaybePromise<void>;
231
+ onDisconnect?: () => MaybePromise<void>;
232
+ messageSchema?: unknown;
233
+ responseSchema?: unknown;
234
+ handlerName?: string;
235
+ }
236
+
237
+ interface Request {
238
+ method: string;
239
+ path: string;
240
+ params: Record<string, string>;
241
+ pathParams: Record<string, string>;
242
+ query: Record<string, string>;
243
+ queryParams: Record<string, string>;
244
+ headers: Record<string, string>;
245
+ cookies: Record<string, string>;
246
+ body: Buffer | null;
247
+ dependencies: Record<string, unknown> | undefined;
248
+ json<T = JsonValue>(): T;
249
+ form(): Record<string, string>;
250
+ }
251
+
252
+ type DependencyValue = unknown;
253
+ type DependencyFactory = (dependencies: Record<string, DependencyValue>) => MaybePromise<DependencyValue>;
254
+ interface DependencyOptions {
255
+ dependsOn?: string[];
256
+ singleton?: boolean;
257
+ cacheable?: boolean;
258
+ }
259
+ interface DependencyDescriptor {
260
+ isFactory: boolean;
261
+ value?: DependencyValue | undefined;
262
+ factory?: DependencyFactory | undefined;
263
+ dependsOn: string[];
264
+ singleton: boolean;
265
+ cacheable: boolean;
266
+ }
267
+ type LifecycleHookPayload = Request | StructuredHandlerResponse;
268
+ type LifecycleHookFunction = (payload: LifecycleHookPayload) => MaybePromise<LifecycleHookPayload>;
269
+ interface LifecycleHooks {
270
+ onRequest: LifecycleHookFunction[];
271
+ preValidation: LifecycleHookFunction[];
272
+ preHandler: LifecycleHookFunction[];
273
+ onResponse: LifecycleHookFunction[];
274
+ onError: LifecycleHookFunction[];
275
+ }
276
+ declare class Spikard implements SpikardApp {
277
+ routes: RouteMetadata[];
278
+ handlers: Record<string, HandlerFunction | NativeHandlerFunction>;
279
+ websocketRoutes: RouteMetadata[];
280
+ websocketHandlers: Record<string, Record<string, unknown>>;
281
+ grpcMethods: GrpcMethodRegistration[];
282
+ grpcHandlers: Record<string, Record<string, unknown>>;
283
+ lifecycleHooks: LifecycleHooks;
284
+ dependencies: Record<string, DependencyDescriptor>;
285
+ addRoute(metadata: RouteMetadata, handler: HandlerFunction | NativeHandlerFunction): void;
286
+ websocket(path: string, handler: WebSocketHandler, options?: WebSocketOptions): void;
287
+ addGrpcUnary(serviceName: string, methodName: string, handler: GrpcHandler): this;
288
+ addGrpcServerStreaming(serviceName: string, methodName: string, handler: GrpcServerStreamingHandler): this;
289
+ addGrpcClientStreaming(serviceName: string, methodName: string, handler: GrpcClientStreamingHandler): this;
290
+ addGrpcBidirectionalStreaming(serviceName: string, methodName: string, handler: GrpcBidirectionalStreamingHandler): this;
291
+ private registerGrpcMethod;
292
+ useGrpc(service: GrpcService): this;
293
+ run(config?: ServerConfig): void;
294
+ onRequest(hook: LifecycleHookFunction): LifecycleHookFunction;
295
+ preValidation(hook: LifecycleHookFunction): LifecycleHookFunction;
296
+ preHandler(hook: LifecycleHookFunction): LifecycleHookFunction;
297
+ onResponse(hook: LifecycleHookFunction): LifecycleHookFunction;
298
+ onError(hook: LifecycleHookFunction): LifecycleHookFunction;
299
+ provide(key: string, valueOrFactory: DependencyValue | DependencyFactory, options?: DependencyOptions): this;
300
+ getLifecycleHooks(): LifecycleHooks;
301
+ }
302
+
303
+ declare function run(work: () => void | Promise<void>): void;
304
+
305
+ declare const background_run: typeof run;
306
+ declare namespace background {
307
+ export { background_run as run };
308
+ }
309
+
253
310
  declare function wrapHandler(handler: HandlerFunction): NativeHandlerFunction;
254
311
  declare function wrapBodyHandler<TBody = unknown>(handler: (body: TBody, request: Request) => MaybePromise<HandlerResult>): NativeHandlerFunction;
255
312
 
@@ -273,6 +330,8 @@ declare function put(path: string, options?: Omit<RouteOptions, "methods">): (ha
273
330
  declare function del(path: string, options?: Omit<RouteOptions, "methods">): (handler: RouteHandler) => RouteHandler;
274
331
  declare function patch(path: string, options?: Omit<RouteOptions, "methods">): (handler: RouteHandler) => RouteHandler;
275
332
 
333
+ declare function runServer(app: SpikardApp, config?: ServerConfig): void;
334
+
276
335
  interface NativeTestResponse {
277
336
  statusCode: number;
278
337
  headers(): Record<string, string>;
@@ -292,6 +351,13 @@ interface WebSocketTestConnection {
292
351
  close(): Promise<void>;
293
352
  }
294
353
  type TestResponse = NativeTestResponse;
354
+ interface GraphQLSubscriptionResult {
355
+ operationId: string;
356
+ acknowledged: boolean;
357
+ event: unknown | null;
358
+ errors: unknown[];
359
+ completeReceived: boolean;
360
+ }
295
361
  interface MultipartFile {
296
362
  name: string;
297
363
  filename?: string;
@@ -330,6 +396,7 @@ declare class TestClient {
330
396
  headers: string;
331
397
  bodyText: string;
332
398
  }>;
399
+ graphqlSubscription(query: string, variables?: Record<string, unknown> | null, operationName?: string | null, path?: string): Promise<GraphQLSubscriptionResult>;
333
400
  cleanup(): Promise<void>;
334
401
  }
335
402
 
@@ -387,14 +454,22 @@ interface RouteMetadata {
387
454
  is_async: boolean;
388
455
  cors?: CorsConfig | undefined;
389
456
  }
457
+ interface GrpcMethodRegistration {
458
+ serviceName: string;
459
+ methodName: string;
460
+ rpcMode: GrpcRpcMode;
461
+ handlerName: string;
462
+ }
390
463
  interface SpikardApp {
391
464
  routes: RouteMetadata[];
392
465
  handlers: Record<string, HandlerFunction | NativeHandlerFunction>;
393
466
  websocketRoutes?: RouteMetadata[];
394
467
  websocketHandlers?: Record<string, Record<string, unknown>>;
468
+ grpcMethods?: GrpcMethodRegistration[];
469
+ grpcHandlers?: Record<string, Record<string, unknown>>;
395
470
  config?: ServerConfig;
396
471
  lifecycleHooks?: Partial<LifecycleHooks>;
397
472
  dependencies?: Record<string, unknown>;
398
473
  }
399
474
 
400
- export { type ApiKeyConfig, type Base64EncodedBody, type Body, type CompressionConfig, type ContactInfo, type CorsConfig, type DependencyFactory, type DependencyOptions, type DependencyValue, type FileParam, GrpcError, type GrpcHandler, type GrpcMetadata, type GrpcRequest, type GrpcResponse, type GrpcServiceConfig, GrpcStatusCode, type HandlerFunction, type HandlerResult, type JsonPrimitive, type JsonRecord, type JsonSchema, type JsonValue, type JwtConfig, type LicenseInfo, type LifecycleHookFunction, type LifecycleHooks, type MaybePromise, type NativeHandlerFunction, type OpenApiConfig, type Path, type Query, QueryDefault, type RateLimitConfig, type Request, type RouteMetadata, type RouteOptions, type SecuritySchemeInfo, type ServerConfig, type ServerInfo, type ServerOptions, Spikard, type SpikardApp, type StaticFilesConfig, StreamingResponse, type StreamingResponseInit, type StructuredHandlerResponse, TestClient, type TestResponse, UploadFile, type WebSocketHandler, type WebSocketOptions, background, createServiceHandler, createUnaryHandler, del, get, patch, post, put, route, runServer, wrapBodyHandler, wrapHandler };
475
+ export { type ApiKeyConfig, type Base64EncodedBody, type Body, type CompressionConfig, type ContactInfo, type CorsConfig, type DependencyFactory, type DependencyOptions, type DependencyValue, type FileParam, type GrpcBidiStreamRequest, type GrpcBidiStreamResponse, type GrpcBidirectionalStreamingHandler, type GrpcClientStreamRequest, type GrpcClientStreamingHandler, GrpcError, type GrpcHandler, type GrpcMetadata, type GrpcMethodConfig, type GrpcMethodHandler, type GrpcMethodRegistration, type GrpcRequest, type GrpcResponse, type GrpcRpcMode, type GrpcServerStreamResponse, type GrpcServerStreamingHandler, GrpcService, GrpcStatusCode, type HandlerFunction, type HandlerResult, type JsonPrimitive, type JsonRecord, type JsonRpcConfig, type JsonSchema, type JsonValue, type JwtConfig, type LicenseInfo, type LifecycleHookFunction, type LifecycleHooks, type MaybePromise, type NativeHandlerFunction, type OpenApiConfig, type Path, type Query, QueryDefault, type RateLimitConfig, type Request, type RouteMetadata, type RouteOptions, type SecuritySchemeInfo, type ServerConfig, type ServerInfo, Spikard, type SpikardApp, type StaticFilesConfig, StreamingResponse, type StreamingResponseInit, type StructuredHandlerResponse, TestClient, type TestResponse, UploadFile, type WebSocketHandler, type WebSocketOptions, background, createServiceHandler, createUnaryHandler, del, get, patch, post, put, route, runServer, wrapBodyHandler, wrapHandler };