ts-typed-api 0.2.13 → 0.2.14

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/dist/handler.d.ts CHANGED
@@ -1,12 +1,13 @@
1
1
  import { ApiDefinitionSchema } from "./definition";
2
2
  import { createRouteHandler } from "./router";
3
+ import { MiddlewareResponse } from "./object-handlers";
3
4
  import express from "express";
4
5
  export type SpecificRouteHandler<TDef extends ApiDefinitionSchema> = {
5
6
  [TDomain_ in keyof TDef['endpoints']]: {
6
7
  [TRouteKey_ in keyof TDef['endpoints'][TDomain_]]: ReturnType<typeof createRouteHandler<TDef, TDomain_, TRouteKey_>>;
7
8
  }[keyof TDef['endpoints'][TDomain_]];
8
9
  }[keyof TDef['endpoints']];
9
- export type EndpointMiddleware<TDef extends ApiDefinitionSchema = ApiDefinitionSchema> = (req: express.Request, res: express.Response, next: express.NextFunction, endpointInfo: {
10
+ export type EndpointMiddleware<TDef extends ApiDefinitionSchema = ApiDefinitionSchema> = (req: express.Request, res: MiddlewareResponse, next: express.NextFunction, endpointInfo: {
10
11
  [TDomain in keyof TDef['endpoints']]: {
11
12
  domain: TDomain;
12
13
  routeKey: keyof TDef['endpoints'][TDomain];
package/dist/handler.js CHANGED
@@ -412,10 +412,11 @@ middlewares) {
412
412
  const wrappedMiddleware = async (req, res, next) => {
413
413
  try {
414
414
  // Add respond method to res for middleware compatibility
415
- res.respond = createRespondFunction(routeDefinition, (status, data) => {
415
+ const middlewareRes = res;
416
+ middlewareRes.respond = createRespondFunction(routeDefinition, (status, data) => {
416
417
  res.status(status).json(data);
417
418
  });
418
- await middleware(req, res, next, { domain: currentDomain, routeKey: currentRouteKey });
419
+ await middleware(req, middlewareRes, next, { domain: currentDomain, routeKey: currentRouteKey });
419
420
  }
420
421
  catch (error) {
421
422
  next(error);
@@ -457,6 +457,20 @@ function registerHonoRouteHandlers(app, apiDefinition, routeHandlers, middleware
457
457
  error: [{ field: "general", type: "general", message: "Internal server error: Constructed response failed validation." }]
458
458
  }, 500);
459
459
  }
460
+ },
461
+ status: (status) => {
462
+ // For middleware that might use status, but since not used, stub
463
+ c.__response = new Response(null, { status: status });
464
+ },
465
+ json: (data) => {
466
+ // Send json response
467
+ c.__response = c.json(data);
468
+ },
469
+ setHeader: (name, value) => {
470
+ c.header(name, value);
471
+ },
472
+ end: () => {
473
+ // Perhaps do nothing or set response
460
474
  }
461
475
  };
462
476
  // Call Express-style middleware
@@ -7,15 +7,22 @@ export type EndpointInfo<TDef extends ApiDefinitionSchema = ApiDefinitionSchema>
7
7
  routeKey: keyof TDef['endpoints'][TDomain];
8
8
  };
9
9
  }[keyof TDef['endpoints']];
10
- export type EndpointMiddleware<TDef extends ApiDefinitionSchema = ApiDefinitionSchema> = (req: express.Request, res: express.Response, next: express.NextFunction, endpointInfo: EndpointInfo<TDef>) => void | Promise<void>;
11
- export type SimpleMiddleware = (req: express.Request, res: express.Response, next: express.NextFunction) => void | Promise<void>;
12
- export type UniversalEndpointMiddleware = (req: express.Request, res: express.Response, next: express.NextFunction, endpointInfo: {
10
+ export type EndpointMiddleware<TDef extends ApiDefinitionSchema = ApiDefinitionSchema> = (req: express.Request, res: MiddlewareResponse, next: express.NextFunction, endpointInfo: EndpointInfo<TDef>) => void | Promise<void>;
11
+ export type SimpleMiddleware = (req: express.Request, res: MiddlewareResponse, next: express.NextFunction) => void | Promise<void>;
12
+ export type UniversalEndpointMiddleware = (req: express.Request, res: MiddlewareResponse, next: express.NextFunction, endpointInfo: {
13
13
  domain: string;
14
14
  routeKey: string;
15
15
  }) => void | Promise<void>;
16
+ export interface MiddlewareResponse {
17
+ respond(status: number, data: any): void;
18
+ status(code: number): this;
19
+ json(data: any): void;
20
+ setHeader(name: string, value: string): void;
21
+ end(): void;
22
+ }
16
23
  export type EndpointMiddlewareCtx<Ctx extends Record<string, any> = Record<string, any>, TDef extends ApiDefinitionSchema = ApiDefinitionSchema> = ((req: express.Request & {
17
24
  ctx?: Ctx;
18
- }, res: express.Response, next: express.NextFunction, endpointInfo: EndpointInfo<TDef>) => void | Promise<void>) | ((c: any, next: any) => void | Promise<void>);
25
+ }, res: MiddlewareResponse, next: express.NextFunction, endpointInfo: EndpointInfo<TDef>) => void | Promise<void>) | ((c: any, next: any) => void | Promise<void>);
19
26
  export type AnyMiddleware<TDef extends ApiDefinitionSchema = ApiDefinitionSchema> = EndpointMiddleware<TDef> | UniversalEndpointMiddleware | SimpleMiddleware;
20
27
  type HandlerFunction<TDef extends ApiDefinitionSchema, TDomain extends keyof TDef['endpoints'], TRouteKey extends keyof TDef['endpoints'][TDomain], Ctx extends Record<string, any> = Record<string, any>> = (req: TypedRequest<TDef, TDomain, TRouteKey, ApiParams<TDef, TDomain, TRouteKey>, ApiBody<TDef, TDomain, TRouteKey>, ApiQuery<TDef, TDomain, TRouteKey>, Record<string, any>, Ctx>, res: TypedResponse<TDef, TDomain, TRouteKey>) => Promise<void> | void;
21
28
  export type ObjectHandlers<TDef extends ApiDefinitionSchema, Ctx extends Record<string, any> = Record<string, any>> = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ts-typed-api",
3
- "version": "0.2.13",
3
+ "version": "0.2.14",
4
4
  "description": "A lightweight, type-safe RPC library for TypeScript with Zod validation",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/src/handler.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { z } from "zod";
2
2
  import { ApiDefinitionSchema, RouteSchema, UnifiedError, FileUploadConfig } from "./definition";
3
3
  import { createRouteHandler, TypedRequest, TypedResponse } from "./router";
4
+ import { MiddlewareResponse } from "./object-handlers";
4
5
  import express from "express";
5
6
  import multer from "multer";
6
7
 
@@ -16,7 +17,7 @@ export type SpecificRouteHandler<TDef extends ApiDefinitionSchema> = {
16
17
  // Type for middleware function that receives endpoint information with type safety
17
18
  export type EndpointMiddleware<TDef extends ApiDefinitionSchema = ApiDefinitionSchema> = (
18
19
  req: express.Request,
19
- res: express.Response,
20
+ res: MiddlewareResponse,
20
21
  next: express.NextFunction,
21
22
  endpointInfo: {
22
23
  [TDomain in keyof TDef['endpoints']]: {
@@ -474,10 +475,11 @@ export function registerRouteHandlers<TDef extends ApiDefinitionSchema>(
474
475
  const wrappedMiddleware: express.RequestHandler = async (req, res, next) => {
475
476
  try {
476
477
  // Add respond method to res for middleware compatibility
477
- (res as any).respond = createRespondFunction(routeDefinition, (status, data) => {
478
+ const middlewareRes = res as any;
479
+ middlewareRes.respond = createRespondFunction(routeDefinition, (status, data) => {
478
480
  res.status(status).json(data);
479
481
  });
480
- await middleware(req, res, next, { domain: currentDomain, routeKey: currentRouteKey } as any);
482
+ await middleware(req, middlewareRes as MiddlewareResponse, next, { domain: currentDomain, routeKey: currentRouteKey } as any);
481
483
  } catch (error) {
482
484
  next(error);
483
485
  }
@@ -546,6 +546,20 @@ export function registerHonoRouteHandlers<
546
546
  error: [{ field: "general", type: "general", message: "Internal server error: Constructed response failed validation." }]
547
547
  }, 500);
548
548
  }
549
+ },
550
+ status: (status: number) => {
551
+ // For middleware that might use status, but since not used, stub
552
+ (c as any).__response = new Response(null, { status: status });
553
+ },
554
+ json: (data: any) => {
555
+ // Send json response
556
+ (c as any).__response = c.json(data);
557
+ },
558
+ setHeader: (name: string, value: string) => {
559
+ c.header(name, value);
560
+ },
561
+ end: () => {
562
+ // Perhaps do nothing or set response
549
563
  }
550
564
  };
551
565
 
@@ -13,7 +13,7 @@ export type EndpointInfo<TDef extends ApiDefinitionSchema = ApiDefinitionSchema>
13
13
  // Type for middleware function that receives endpoint information
14
14
  export type EndpointMiddleware<TDef extends ApiDefinitionSchema = ApiDefinitionSchema> = (
15
15
  req: express.Request,
16
- res: express.Response,
16
+ res: MiddlewareResponse,
17
17
  next: express.NextFunction,
18
18
  endpointInfo: EndpointInfo<TDef>
19
19
  ) => void | Promise<void>;
@@ -21,14 +21,14 @@ export type EndpointMiddleware<TDef extends ApiDefinitionSchema = ApiDefinitionS
21
21
  // Type for simple middleware that doesn't need endpoint information
22
22
  export type SimpleMiddleware = (
23
23
  req: express.Request,
24
- res: express.Response,
24
+ res: MiddlewareResponse,
25
25
  next: express.NextFunction
26
26
  ) => void | Promise<void>;
27
27
 
28
28
  // Type for middleware that can work with any API definition
29
29
  export type UniversalEndpointMiddleware = (
30
30
  req: express.Request,
31
- res: express.Response,
31
+ res: MiddlewareResponse,
32
32
  next: express.NextFunction,
33
33
  endpointInfo: {
34
34
  domain: string;
@@ -36,13 +36,22 @@ export type UniversalEndpointMiddleware = (
36
36
  }
37
37
  ) => void | Promise<void>;
38
38
 
39
+ // Custom response interface for framework-agnostic middleware
40
+ export interface MiddlewareResponse {
41
+ respond(status: number, data: any): void;
42
+ status(code: number): this;
43
+ json(data: any): void;
44
+ setHeader(name: string, value: string): void;
45
+ end(): void;
46
+ }
47
+
39
48
  // Unified middleware type that works for both Express and Hono with context typing
40
49
  export type EndpointMiddlewareCtx<
41
50
  Ctx extends Record<string, any> = Record<string, any>,
42
51
  TDef extends ApiDefinitionSchema = ApiDefinitionSchema
43
52
  > =
44
53
  // Express version: (req, res, next, endpointInfo)
45
- ((req: express.Request & { ctx?: Ctx }, res: express.Response, next: express.NextFunction, endpointInfo: EndpointInfo<TDef>) => void | Promise<void>) |
54
+ ((req: express.Request & { ctx?: Ctx }, res: MiddlewareResponse, next: express.NextFunction, endpointInfo: EndpointInfo<TDef>) => void | Promise<void>) |
46
55
  // Hono version: (c, next) - context is passed via c.req.ctx -> c.ctx copying
47
56
  ((c: any, next: any) => void | Promise<void>);
48
57
 
package/tests/setup.ts CHANGED
@@ -7,6 +7,7 @@ import { PublicApiDefinition as SimplePublicApiDefinition, PrivateApiDefinition
7
7
  import { PublicApiDefinition as AdvancedPublicApiDefinition, PrivateApiDefinition as AdvancedPrivateApiDefinition } from '../examples/advanced/definitions';
8
8
  import { RegisterHandlers, RegisterHonoHandlers, CreateApiDefinition, CreateResponses, CreateTypedHonoHandlerWithContext } from '../src';
9
9
  import { z } from 'zod';
10
+ import { EndpointMiddlewareCtx } from '../src/object-handlers';
10
11
 
11
12
  // Shared handler definitions for simple API
12
13
  const simplePublicHandlers = {
@@ -444,7 +445,7 @@ async function startHonoServer(): Promise<void> {
444
445
  });
445
446
  }
446
447
 
447
- type Ctx = { user?: string; noAuth?: boolean; forbidden?: boolean }
448
+ type Ctx = { user?: string; noAuth?: boolean; forbidden?: boolean, middlewareData?: string }
448
449
 
449
450
  // Shared handlers for middleware tests
450
451
  const middlewareTestHandlers = {
@@ -471,74 +472,45 @@ const middlewareTestHandlers = {
471
472
  // Generic middleware setup function
472
473
  function setupMiddlewareApp(app: any, isHono: boolean) {
473
474
  // Define middleware functions
474
- const loggingMiddleware = isHono ?
475
- async (req: any, res: any, next: any, endpointInfo: any) => {
476
- console.log(`[Test Hono] ${req.method} ${req.path} - Domain: ${endpointInfo.domain}, Route: ${endpointInfo.routeKey}`);
477
- await next();
478
- } :
479
- (req: express.Request, res: express.Response, next: express.NextFunction, endpointInfo: any) => {
480
- console.log(`[Test] ${req.method} ${req.path} - Domain: ${endpointInfo.domain}, Route: ${endpointInfo.routeKey}`);
481
- next();
482
- };
483
-
484
- const contextMiddleware = isHono ?
485
- async (req: any, res: any, next: any) => {
486
- req.ctx = { ...req.ctx, middlewareData: "middleware-added-data" };
487
- await next();
488
- } :
489
- (req: express.Request, res: express.Response, next: express.NextFunction) => {
490
- (req as any).ctx = { middlewareData: "middleware-added-data" };
491
- next();
492
- };
493
-
494
- const authMiddleware = isHono ?
495
- async (req: any, res: any, next: any, endpointInfo: any) => {
496
- // Only apply auth checks to protected routes
497
- if (endpointInfo.domain === 'public' && endpointInfo.routeKey === 'protected') {
498
- const authHeader = req.headers?.authorization;
499
- if (!authHeader) {
500
- (res as any).respond(401, { error: "No authorization header" });
501
- } else if (authHeader === 'Bearer valid-token') {
502
- req.ctx = { ...req.ctx, user: 'testuser' };
503
- await next();
504
- } else {
505
- (res as any).respond(403, { error: "Forbidden" });
506
- }
507
- } else {
475
+ const loggingMiddleware: EndpointMiddlewareCtx<Ctx> = async (req, res, next, endpointInfo) => {
476
+ console.log(`[Test] ${req.method} ${req.path} - Domain: ${endpointInfo.domain}, Route: ${endpointInfo.routeKey}`);
477
+ await next();
478
+ }
479
+
480
+ const contextMiddleware: EndpointMiddlewareCtx<Ctx> = async (req, res, next) => {
481
+ req.ctx = { ...req.ctx, middlewareData: "middleware-added-data" };
482
+ await next();
483
+ }
484
+
485
+ const authMiddleware: EndpointMiddlewareCtx<Ctx> = async (req, res, next, endpointInfo) => {
486
+ // Only apply auth checks to protected routes
487
+ if (endpointInfo.domain === 'public' && endpointInfo.routeKey === 'protected') {
488
+ const authHeader = req.headers?.authorization;
489
+ if (!authHeader) {
490
+ res.respond(401, { error: "No authorization header" });
491
+ } else if (authHeader === 'Bearer valid-token') {
492
+ req.ctx = { ...req.ctx, user: 'testuser' };
508
493
  await next();
509
- }
510
- } :
511
- (req: any, res: any, next: any, endpointInfo: any) => {
512
- // Only apply auth checks to protected routes
513
- if (endpointInfo.domain === 'public' && endpointInfo.routeKey === 'protected') {
514
- const authHeader = req.headers?.authorization;
515
- if (!authHeader) {
516
- (res as any).respond(401, { error: "No authorization header" });
517
- } else if (authHeader === 'Bearer valid-token') {
518
- req.ctx = { ...req.ctx, user: 'testuser' };
519
- next();
520
- } else {
521
- (res as any).respond(403, { error: "Forbidden" });
522
- }
523
494
  } else {
524
- next();
495
+ res.respond(403, { error: "Forbidden" });
525
496
  }
526
- };
497
+ } else {
498
+ await next();
499
+ }
500
+ }
501
+
502
+ const middlewares = [
503
+ loggingMiddleware,
504
+ contextMiddleware,
505
+ authMiddleware
506
+ ]
527
507
 
528
508
  // Register handlers with middleware
529
509
  if (isHono) {
530
510
  const hndl = CreateTypedHonoHandlerWithContext<Ctx>();
531
- hndl(app, MiddlewareTestApiDefinition, middlewareTestHandlers, [
532
- loggingMiddleware,
533
- contextMiddleware,
534
- authMiddleware
535
- ]);
511
+ hndl(app, MiddlewareTestApiDefinition, middlewareTestHandlers, middlewares);
536
512
  } else {
537
- RegisterHandlers(app, MiddlewareTestApiDefinition, middlewareTestHandlers, [
538
- loggingMiddleware,
539
- contextMiddleware,
540
- authMiddleware
541
- ]);
513
+ RegisterHandlers(app, MiddlewareTestApiDefinition, middlewareTestHandlers, middlewares);
542
514
  }
543
515
  }
544
516