This repository has no description
1import { error, type NumericRange } from "@sveltejs/kit";
2import { ClientResponseError } from "./client";
3
4export const httpStatusFor = (cause: unknown): number => {
5 if (cause instanceof ClientResponseError) {
6 if (cause.status >= 400 && cause.status <= 599) return cause.status;
7 switch (cause.error) {
8 case "RecordNotFound":
9 return 404;
10 case "InvalidRequest":
11 return 400;
12 case "UpstreamFailed":
13 case "UpstreamGone":
14 case "InvalidRecord":
15 return 502;
16 case "Overloaded":
17 return 503;
18 default:
19 return 500;
20 }
21 }
22 return 500;
23};
24
25export const errorMessage = (cause: unknown, fallbackMessage = "Request failed"): string =>
26 cause instanceof ClientResponseError ? (cause.description ?? cause.error) : fallbackMessage;
27
28export const toHttpError = (cause: unknown, fallbackMessage = "Request failed"): never => {
29 const status = httpStatusFor(cause) as NumericRange<400, 599>;
30 throw error(status, errorMessage(cause, fallbackMessage));
31};
32
33export const parallel = async <T extends Record<string, Promise<unknown>>>(
34 tasks: T
35): Promise<{ [K in keyof T]: Awaited<T[K]> }> => {
36 const keys = Object.keys(tasks) as (keyof T)[];
37 const values = await Promise.all(keys.map((key) => tasks[key]));
38 const out = {} as { [K in keyof T]: Awaited<T[K]> };
39 keys.forEach((key, index) => {
40 out[key] = values[index] as Awaited<T[keyof T]>;
41 });
42 return out;
43};
44
45// per-request promise de-dupe cache.
46export interface RequestCache {
47 run<T>(key: string, load: () => Promise<T>): Promise<T>;
48}
49
50export const createRequestCache = (): RequestCache => {
51 const entries = new Map<string, Promise<unknown>>();
52 return {
53 run<T>(key: string, load: () => Promise<T>): Promise<T> {
54 const existing = entries.get(key) as Promise<T> | undefined;
55 if (existing) return existing;
56 const pending = load();
57 entries.set(key, pending);
58 return pending;
59 }
60 };
61};