better-call 1.1.3 → 1.1.5

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/index.js CHANGED
@@ -115,6 +115,17 @@ var InternalAPIError = class extends Error {
115
115
  } : void 0;
116
116
  }
117
117
  };
118
+ var ValidationError = class extends InternalAPIError {
119
+ constructor(message, issues) {
120
+ super(400, {
121
+ message,
122
+ code: "VALIDATION_ERROR"
123
+ });
124
+ this.message = message;
125
+ this.issues = issues;
126
+ this.issues = issues;
127
+ }
128
+ };
118
129
  var BetterCallError = class extends Error {
119
130
  constructor(message) {
120
131
  super(message);
@@ -179,6 +190,19 @@ function tryDecode(str) {
179
190
  return str;
180
191
  }
181
192
  }
193
+ async function tryCatch(promise) {
194
+ try {
195
+ return {
196
+ data: await promise,
197
+ error: null
198
+ };
199
+ } catch (error) {
200
+ return {
201
+ data: null,
202
+ error
203
+ };
204
+ }
205
+ }
182
206
 
183
207
  //#endregion
184
208
  //#region src/to-response.ts
@@ -300,11 +324,17 @@ async function runValidation(options, context = {}) {
300
324
  }
301
325
  if (options.requireHeaders && !context.headers) return {
302
326
  data: null,
303
- error: { message: "Headers is required" }
327
+ error: {
328
+ message: "Headers is required",
329
+ issues: []
330
+ }
304
331
  };
305
332
  if (options.requireRequest && !context.request) return {
306
333
  data: null,
307
- error: { message: "Request is required" }
334
+ error: {
335
+ message: "Request is required",
336
+ issues: []
337
+ }
308
338
  };
309
339
  return {
310
340
  data: request,
@@ -312,12 +342,12 @@ async function runValidation(options, context = {}) {
312
342
  };
313
343
  }
314
344
  function fromError(error, validating) {
315
- const errorMessages = [];
316
- for (const issue of error) {
317
- const message = issue.message;
318
- errorMessages.push(message);
319
- }
320
- return { message: `Invalid ${validating} parameters` };
345
+ return {
346
+ message: error.map((e) => {
347
+ return `[${e.path?.length ? `${validating}.` + e.path.map((x) => typeof x === "object" ? x.key : x).join(".") : validating}] ${e.message}`;
348
+ }).join("; "),
349
+ issues: error
350
+ };
321
351
  }
322
352
 
323
353
  //#endregion
@@ -437,10 +467,7 @@ const createInternalContext = async (context, { options, path }) => {
437
467
  const headers = new Headers();
438
468
  let responseStatus = void 0;
439
469
  const { data, error } = await runValidation(options, context);
440
- if (error) throw new APIError(400, {
441
- message: error.message,
442
- code: "VALIDATION_ERROR"
443
- });
470
+ if (error) throw new ValidationError(error.message, error.issues);
444
471
  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;
445
472
  const requestCookies = requestHeaders?.get("cookie");
446
473
  const parsedCookies = requestCookies ? parseCookies(requestCookies) : void 0;
@@ -536,12 +563,24 @@ function createEndpoint(pathOrOptions, handlerOrOptions, handlerOrNever) {
536
563
  const options = typeof handlerOrOptions === "object" ? handlerOrOptions : pathOrOptions;
537
564
  const handler = typeof handlerOrOptions === "function" ? handlerOrOptions : handlerOrNever;
538
565
  if ((options.method === "GET" || options.method === "HEAD") && options.body) throw new BetterCallError("Body is not allowed with GET or HEAD methods");
566
+ if (path && /\/{2,}/.test(path)) throw new BetterCallError("Path cannot contain consecutive slashes");
539
567
  const internalHandler = async (...inputCtx) => {
540
568
  const context = inputCtx[0] || {};
541
- const internalContext = await createInternalContext(context, {
569
+ const { data: internalContext, error: validationError } = await tryCatch(createInternalContext(context, {
542
570
  options,
543
571
  path
544
- });
572
+ }));
573
+ if (validationError) {
574
+ if (!(validationError instanceof ValidationError)) throw validationError;
575
+ if (options.onValidationError) await options.onValidationError({
576
+ message: validationError.message,
577
+ issues: validationError.issues
578
+ });
579
+ throw new APIError(400, {
580
+ message: validationError.message,
581
+ code: "VALIDATION_ERROR"
582
+ });
583
+ }
545
584
  const response = await handler(internalContext).catch(async (e) => {
546
585
  if (isAPIError(e)) {
547
586
  const onAPIError = options.onAPIError;
@@ -823,7 +862,8 @@ const createRouter = (endpoints, config) => {
823
862
  if (config?.routerMiddleware?.length) for (const { path, middleware } of config.routerMiddleware) addRoute(middlewareRouter, "*", path, middleware);
824
863
  const processRequest = async (request) => {
825
864
  const url = new URL(request.url);
826
- const path = config?.basePath ? url.pathname.split(config.basePath).reduce((acc, curr, index) => {
865
+ const pathname = url.pathname;
866
+ const path = config?.basePath && config.basePath !== "/" ? pathname.split(config.basePath).reduce((acc, curr, index) => {
827
867
  if (index !== 0) if (index > 1) acc.push(`${config.basePath}${curr}`);
828
868
  else acc.push(curr);
829
869
  return acc;
@@ -832,7 +872,15 @@ const createRouter = (endpoints, config) => {
832
872
  status: 404,
833
873
  statusText: "Not Found"
834
874
  });
875
+ if (/\/{2,}/.test(path)) return new Response(null, {
876
+ status: 404,
877
+ statusText: "Not Found"
878
+ });
835
879
  const route = findRoute(router, request.method, path);
880
+ if (path.endsWith("/") !== route?.data?.path?.endsWith("/") && !config?.skipTrailingSlashes) return new Response(null, {
881
+ status: 404,
882
+ statusText: "Not Found"
883
+ });
836
884
  if (!route?.data) return new Response(null, {
837
885
  status: 404,
838
886
  statusText: "Not Found"
@@ -899,5 +947,5 @@ const createRouter = (endpoints, config) => {
899
947
  };
900
948
 
901
949
  //#endregion
902
- export { APIError, BetterCallError, createEndpoint, createInternalContext, createMiddleware, createRouter, generator, getCookieKey, getHTML, hideInternalStackFrames, makeErrorForHideStackFrame, parseCookies, serializeCookie, serializeSignedCookie, statusCodes, toResponse };
950
+ export { APIError, BetterCallError, ValidationError, createEndpoint, createInternalContext, createMiddleware, createRouter, generator, getCookieKey, getHTML, hideInternalStackFrames, makeErrorForHideStackFrame, parseCookies, serializeCookie, serializeSignedCookie, statusCodes, toResponse };
903
951
  //# sourceMappingURL=index.js.map