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 toHttpError = (cause: unknown, fallbackMessage = "Request failed"): never => {
26 const status = httpStatusFor(cause) as NumericRange<400, 599>;
27 const message =
28 cause instanceof ClientResponseError ? (cause.description ?? cause.error) : fallbackMessage;
29 throw error(status, message);
30};
31
32export const parallel = async <T extends Record<string, Promise<unknown>>>(
33 tasks: T
34): Promise<{ [K in keyof T]: Awaited<T[K]> }> => {
35 const keys = Object.keys(tasks) as (keyof T)[];
36 const values = await Promise.all(keys.map((key) => tasks[key]));
37 const out = {} as { [K in keyof T]: Awaited<T[K]> };
38 keys.forEach((key, index) => {
39 out[key] = values[index] as Awaited<T[keyof T]>;
40 });
41 return out;
42};
43
44// per-request promise de-dupe cache.
45export interface RequestCache {
46 run<T>(key: string, load: () => Promise<T>): Promise<T>;
47}
48
49export const createRequestCache = (): RequestCache => {
50 const entries = new Map<string, Promise<unknown>>();
51 return {
52 run<T>(key: string, load: () => Promise<T>): Promise<T> {
53 const existing = entries.get(key) as Promise<T> | undefined;
54 if (existing) return existing;
55 const pending = load();
56 entries.set(key, pending);
57 return pending;
58 }
59 };
60};