better-call 1.0.25-beta.2 → 1.0.25

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
@@ -78,7 +78,27 @@ const items = await client("/item", {
78
78
 
79
79
  ### Returning non 200 responses
80
80
 
81
- To return a non 200 response, you will need to throw Better Call's `APIError` error. If the endpoint is called as a function, the error will be thrown but if it's mounted to a router, the error will be converted to a response object with the correct status code and headers.
81
+ There are several supported ways to a non 200 response:
82
+
83
+ You can use the `ctx.setStatus(status)` helper to change the default status code of a successful response:
84
+
85
+ ```ts
86
+ const createItem = createEndpoint("/item", {
87
+ method: "POST",
88
+ body: z.object({
89
+ id: z.string()
90
+ })
91
+ }, async (ctx) => {
92
+ ctx.setStatus(201);
93
+ return {
94
+ item: {
95
+ id: ctx.body.id
96
+ }
97
+ }
98
+ })
99
+ ```
100
+
101
+ Sometimes, you want to respond with an error, in those cases you will need to throw Better Call's `APIError` error. If the endpoint is called as a function, the error will be thrown but if it's mounted to a router, the error will be converted to a response object with the correct status code and headers.
82
102
 
83
103
  ```ts
84
104
  const createItem = createEndpoint("/item", {
@@ -122,6 +142,23 @@ const createItem = createEndpoint("/item", {
122
142
  })
123
143
  ```
124
144
 
145
+ Finally, you can return a new `Response` object. In this case, the `ctx.setStatus()` call will be ignored, as the `Response` will have completely control over the final status code:
146
+
147
+ ```ts
148
+ const createItem = createEndpoint("/item", {
149
+ method: "POST",
150
+ body: z.object({
151
+ id: z.string()
152
+ })
153
+ }, async (ctx) => {
154
+ return Response.json({
155
+ item: {
156
+ id: ctx.body.id
157
+ }
158
+ }, { status: 201 });
159
+ })
160
+ ```
161
+
125
162
  ### Endpoint
126
163
 
127
164
  Endpoints are building blocks of better-call.
package/dist/client.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { Endpoint, HasRequiredKeys, Router, UnionToIntersection } from "./router-BFJOSfmb.cjs";
1
+ import { Endpoint, HasRequiredKeys, Router, UnionToIntersection } from "./router-DeSuoHCx.cjs";
2
2
  import { BetterFetchOption, BetterFetchResponse } from "@better-fetch/fetch";
3
3
 
4
4
  //#region src/client.d.ts
package/dist/client.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Endpoint, HasRequiredKeys, Router, UnionToIntersection } from "./router-D0KeMgM6.js";
1
+ import { Endpoint, HasRequiredKeys, Router, UnionToIntersection } from "./router-DRUBbubk.js";
2
2
  import { BetterFetchOption, BetterFetchResponse } from "@better-fetch/fetch";
3
3
 
4
4
  //#region src/client.d.ts
package/dist/index.cjs CHANGED
@@ -117,6 +117,12 @@ var InternalAPIError = class extends Error {
117
117
  } : void 0;
118
118
  }
119
119
  };
120
+ var BetterCallError = class extends Error {
121
+ constructor(message) {
122
+ super(message);
123
+ this.name = "BetterCallError";
124
+ }
125
+ };
120
126
  const APIError = makeErrorForHideStackFrame(InternalAPIError, Error);
121
127
 
122
128
  //#endregion
@@ -411,19 +417,20 @@ const serializeSignedCookie = async (key, value, secret, opt) => {
411
417
  //#region src/context.ts
412
418
  const createInternalContext = async (context, { options, path }) => {
413
419
  const headers = new Headers();
420
+ let responseStatus = void 0;
414
421
  const { data, error } = await runValidation(options, context);
415
422
  if (error) throw new APIError(400, {
416
423
  message: error.message,
417
424
  code: "VALIDATION_ERROR"
418
425
  });
419
- const requestHeaders = "headers" in context ? context.headers instanceof Headers ? context.headers : new Headers(context.headers) : "request" in context && context.request instanceof Request ? context.request.headers : null;
420
- const requestCookies = requestHeaders?.get("cookie");
426
+ const requestHeaders = "headers" in context ? context.headers instanceof Headers ? context.headers : new Headers(context.headers) : "request" in context && context.request instanceof Request ? context.request.headers : new Headers();
427
+ const requestCookies = requestHeaders.get("cookie");
421
428
  const parsedCookies = requestCookies ? parseCookies(requestCookies) : void 0;
422
429
  const internalContext = {
423
430
  ...context,
424
431
  body: data.body,
425
432
  query: data.query,
426
- path: context.path || path,
433
+ path,
427
434
  context: "context" in context && context.context ? context.context : {},
428
435
  returned: void 0,
429
436
  headers: context?.headers,
@@ -471,6 +478,9 @@ const createInternalContext = async (context, { options, path }) => {
471
478
  error: (status, body, headers$1) => {
472
479
  return new APIError(status, body, headers$1);
473
480
  },
481
+ setStatus: (status) => {
482
+ responseStatus = status;
483
+ },
474
484
  json: (json, routerResponse) => {
475
485
  if (!context.asResponse) return json;
476
486
  return {
@@ -479,7 +489,10 @@ const createInternalContext = async (context, { options, path }) => {
479
489
  _flag: "json"
480
490
  };
481
491
  },
482
- responseHeaders: headers
492
+ responseHeaders: headers,
493
+ get responseStatus() {
494
+ return responseStatus;
495
+ }
483
496
  };
484
497
  for (const middleware of options.use || []) {
485
498
  const response = await middleware({
@@ -498,43 +511,10 @@ const createInternalContext = async (context, { options, path }) => {
498
511
  return internalContext;
499
512
  };
500
513
 
501
- //#endregion
502
- //#region src/middleware.ts
503
- function createMiddleware(optionsOrHandler, handler) {
504
- const internalHandler = async (inputCtx) => {
505
- const context = inputCtx;
506
- const _handler = typeof optionsOrHandler === "function" ? optionsOrHandler : handler;
507
- const internalContext = await createInternalContext(context, {
508
- options: typeof optionsOrHandler === "function" ? {} : optionsOrHandler,
509
- path: "/"
510
- });
511
- if (!_handler) throw new Error("handler must be defined");
512
- const response = await _handler(internalContext);
513
- const headers = internalContext.responseHeaders;
514
- return context.returnHeaders ? {
515
- headers,
516
- response
517
- } : response;
518
- };
519
- internalHandler.options = typeof optionsOrHandler === "function" ? {} : optionsOrHandler;
520
- return internalHandler;
521
- }
522
- createMiddleware.create = (opts) => {
523
- function fn(optionsOrHandler, handler) {
524
- if (typeof optionsOrHandler === "function") return createMiddleware({ use: opts?.use }, optionsOrHandler);
525
- if (!handler) throw new Error("Middleware handler is required");
526
- return createMiddleware({
527
- ...optionsOrHandler,
528
- method: "*",
529
- use: [...opts?.use || [], ...optionsOrHandler.use || []]
530
- }, handler);
531
- }
532
- return fn;
533
- };
534
-
535
514
  //#endregion
536
515
  //#region src/endpoint.ts
537
516
  const createEndpoint = (path, options, handler) => {
517
+ if ((options.method === "GET" || options.method === "HEAD") && options.body) throw new BetterCallError("Body is not allowed with GET or HEAD methods");
538
518
  const internalHandler = async (...inputCtx) => {
539
519
  const context = inputCtx[0] || {};
540
520
  const internalContext = await createInternalContext(context, {
@@ -550,9 +530,20 @@ const createEndpoint = (path, options, handler) => {
550
530
  throw e;
551
531
  });
552
532
  const headers = internalContext.responseHeaders;
553
- return context.asResponse ? toResponse(response, { headers }) : context.returnHeaders ? {
533
+ const status = internalContext.responseStatus;
534
+ return context.asResponse ? toResponse(response, {
535
+ headers,
536
+ status
537
+ }) : context.returnHeaders ? context.returnStatus ? {
538
+ headers,
539
+ response,
540
+ status
541
+ } : {
554
542
  headers,
555
543
  response
544
+ } : context.returnStatus ? {
545
+ response,
546
+ status
556
547
  } : response;
557
548
  };
558
549
  internalHandler.options = options;
@@ -568,6 +559,40 @@ createEndpoint.create = (opts) => {
568
559
  };
569
560
  };
570
561
 
562
+ //#endregion
563
+ //#region src/middleware.ts
564
+ function createMiddleware(optionsOrHandler, handler) {
565
+ const internalHandler = async (inputCtx) => {
566
+ const context = inputCtx;
567
+ const _handler = typeof optionsOrHandler === "function" ? optionsOrHandler : handler;
568
+ const internalContext = await createInternalContext(context, {
569
+ options: typeof optionsOrHandler === "function" ? {} : optionsOrHandler,
570
+ path: "/"
571
+ });
572
+ if (!_handler) throw new Error("handler must be defined");
573
+ const response = await _handler(internalContext);
574
+ const headers = internalContext.responseHeaders;
575
+ return context.returnHeaders ? {
576
+ headers,
577
+ response
578
+ } : response;
579
+ };
580
+ internalHandler.options = typeof optionsOrHandler === "function" ? {} : optionsOrHandler;
581
+ return internalHandler;
582
+ }
583
+ createMiddleware.create = (opts) => {
584
+ function fn(optionsOrHandler, handler) {
585
+ if (typeof optionsOrHandler === "function") return createMiddleware({ use: opts?.use }, optionsOrHandler);
586
+ if (!handler) throw new Error("Middleware handler is required");
587
+ return createMiddleware({
588
+ ...optionsOrHandler,
589
+ method: "*",
590
+ use: [...opts?.use || [], ...optionsOrHandler.use || []]
591
+ }, handler);
592
+ }
593
+ return fn;
594
+ };
595
+
571
596
  //#endregion
572
597
  //#region node_modules/.pnpm/zod@4.0.1/node_modules/zod/v4/core/core.js
573
598
  /** A special constant with type `never` */
@@ -2521,6 +2546,7 @@ const createRouter = (endpoints, config$1) => {
2521
2546
 
2522
2547
  //#endregion
2523
2548
  exports.APIError = APIError;
2549
+ exports.BetterCallError = BetterCallError;
2524
2550
  exports._statusCode = _statusCode;
2525
2551
  exports.createEndpoint = createEndpoint;
2526
2552
  exports.createInternalContext = createInternalContext;