{"version":3,"sources":["../src/index.ts"],"sourcesContent":["type Paths = {\n    [key: string]: {\n        [key: string]: any;\n    };\n}\n\ntype HTTPMethod =\n    | 'get'\n    | 'put'\n    | 'post'\n    | 'delete'\n    | 'options'\n    | 'head'\n    | 'patch'\n    | 'trace';\n\nexport type PathMethods<paths extends Paths, TPath extends keyof paths> = {\n    [TMethod in HTTPMethod]: paths[TPath][TMethod] extends undefined\n    ? never\n    : TMethod;\n}[HTTPMethod];\n\ntype AnyRequestBody = {\n    content: Record<string, any>;\n};\n\ntype AnyResponses = Record<\n    number,\n    { content?: Record<string, any>; headers?: Record<string, any> }\n>;\n\ntype AnyParameters = {\n    query?: Record<string, any>;\n    header?: Record<string, any>;\n    path?: Record<string, any>;\n    cookie?: Record<string, any>;\n};\n\ntype AnyRoute = {\n    responses: AnyResponses;\n    requestBody?: AnyRequestBody;\n    parameters: AnyParameters;\n};\n\n\ntype Prettify<T> = {\n    [K in keyof T]: T[K];\n} & {};\n\n\nexport type ApiResponse<TResponses extends AnyResponses> = {\n    [TStatus in keyof TResponses]: TStatus extends number\n    ? TResponses[TStatus]['content'] extends undefined\n    ? {\n        status: TStatus;\n        contentType: never;\n        data: never;\n        headers: TResponses[TStatus]['headers'] extends Record<\n            string,\n            unknown\n        >\n        ? Map<\n            keyof TResponses[TStatus]['headers'],\n            TResponses[TStatus]['headers'][keyof TResponses[TStatus]['headers']]\n        >\n        : TResponses[TStatus]['headers'];\n    }\n    : {\n        [K in keyof TResponses[TStatus]['content']]: {\n            status: TStatus;\n            contentType: K;\n            data: TResponses[TStatus]['content'][K];\n            headers: TResponses[TStatus]['headers'] extends Record<\n                string,\n                unknown\n            >\n            ? Map<\n                keyof TResponses[TStatus]['headers'],\n                TResponses[TStatus]['headers'][keyof TResponses[TStatus]['headers']]\n            >\n            : TResponses[TStatus]['headers'];\n        };\n    }[keyof TResponses[TStatus]['content']]\n    : never;\n}[keyof TResponses];\n\nexport type ApiRequestBody<TBody extends AnyRequestBody | undefined> =\n    TBody extends AnyRequestBody\n    ? {\n        [K in keyof TBody['content']]: {\n            contentType: K;\n            data: TBody['content'][K];\n        };\n    }[keyof TBody['content']]\n    : {\n        contentType?: undefined;\n        data?: undefined;\n    };\n\nexport type HeaderObject = Record<string, string>;\nexport type HeaderPredicate = () => PromiseLike<HeaderObject>;\n\nexport type OpenApiHookOptions = {\n    baseUrl: URL | string;\n    headers?: HeaderObject | HeaderPredicate;\n    onError?: (error: ApiError) => void;\n};\n\nexport class ApiError extends Error {\n    // eslint-disable-next-line unused-imports/no-unused-vars\n    constructor(message: string, public status: number) {\n        super(message);\n    }\n\n    static fromResponse(response: Response) {\n        return new ApiError(response.statusText, response.status);\n    }\n}\n\nconst convertBody = (\n    data: any,\n    contentType: string | undefined\n): BodyInit | undefined => {\n    if (contentType === undefined) {\n        return;\n    }\n\n    switch (contentType) {\n        case 'application/json':\n        case 'application/json; charset=utf-8':\n            return JSON.stringify(data);\n        default:\n            throw new Error('Unsupported content type: ' + contentType);\n    }\n};\n\nconst decodeResponse = async (response, responseContentType) => {\n    switch (responseContentType) {\n        // eslint-disable-next-line unicorn/no-null\n        case null:\n            return {\n                status: response.status,\n                headers: response.headers,\n            } as any;\n\n        case 'text/plain; charset=utf-8':\n            return {\n                status: response.status,\n                contentType: responseContentType,\n                data: await response.text(),\n            } as any;\n\n        case 'application/json; charset=utf-8':\n            return {\n                status: response.status,\n                contentType: responseContentType,\n                data: await response.json(),\n                headers: response.headers,\n            } as any;\n        default:\n            throw new Error('Unsupported content type: ' + responseContentType);\n    }\n};\n\nexport const createFetch = <paths extends Paths>(options?: OpenApiHookOptions) => {\n    const { baseUrl = window.location.toString(), headers: defaultHeaders, onError } = options ?? {};\n\n    /**\n     * Makes a type-safe OpenAPI request using fetch\n     *\n     * @description\n     * This function provides a strongly-typed interface for making API requests based on your OpenAPI schema.\n     * It handles authentication, request/response serialization, and error handling automatically.\n     *\n     * @example\n     * Basic GET request:\n     * ```ts\n     * const response = await fetching('/items', 'get', {\n     *   query: { limit: 10, offset: 0 }\n     * });\n     * // response.data is fully typed based on your API schema! 🎉\n     * console.log(response.data.items);\n     * ```\n     *\n     * @example\n     * POST request with JSON body:\n     * ```ts\n     * const response = await fetching('/items', 'post', {\n     *   contentType: 'application/json',\n     *   data: {\n     *     name: 'Cool Item',\n     *     description: 'A very cool item indeed'\n     *   }\n     * });\n     * ```\n     *\n     * @example\n     * Using path parameters:\n     * ```ts\n     * const response = await fetching('/items/{itemId}', 'get', {\n     *   path: { itemId: '123' }\n     * });\n     * ```\n     *\n     * @example\n     * Adding custom headers:\n     * ```ts\n     * const response = await fetching('/items', 'get', {\n     *   header: {\n     *     'X-Custom-Header': 'value'\n     *   }\n     * });\n     * ```\n     *\n     * @example\n     * Handling errors:\n     * ```ts\n     * try {\n     *   const response = await fetching('/items', 'get', {});\n     * } catch (error) {\n     *   if (error instanceof ApiError) {\n     *     console.error(`API Error ${error.status}: ${error.message}`);\n     *   }\n     * }\n     * ```\n     *\n     * @template TPath - The API endpoint path (must exist in your OpenAPI schema)\n     * @template TMethod - The HTTP method to use (must be valid for the given path)\n     * @template TOptions - Request options including query params, headers, and body\n     * @template TRoute - Internal type representing the full route definition\n     *\n     * @param path - The API endpoint path (e.g., '/items')\n     * @param method - The HTTP method to use (e.g., 'get', 'post')\n     * @param options - Request configuration object containing:\n     *   - query?: Record<string, any> - Query parameters\n     *   - header?: Record<string, any> - Custom headers\n     *   - path?: Record<string, any> - Path parameters\n     *   - contentType?: string - Request content type\n     *   - data?: any - Request body\n     *   - fetchOptions?: RequestInit - Additional fetch options\n     *\n     * @returns A Promise resolving to a typed response object containing:\n     *   - status: HTTP status code\n     *   - contentType: Response content type (if applicable)\n     *   - data: Response body (if applicable)\n     *   - headers: Response headers\n     *\n     * @throws {ApiError} When the server returns a non-2xx status code\n     * @throws {Error} When an unsupported content type is encountered\n     */\n    return async <\n        TPath extends keyof paths,\n        TMethod extends PathMethods<paths, TPath>,\n        TOptions extends TRoute['parameters'] & ApiRequestBody<TRoute['requestBody']> & {\n            fetchOptions?: RequestInit;\n        },\n        TRoute extends AnyRoute = paths[TPath][TMethod] extends AnyRoute\n        ? paths[TPath][TMethod]\n        : never,\n    >(\n        path: TPath,\n        method: TMethod,\n        options: TOptions\n    ): Promise<Prettify<ApiResponse<TRoute['responses']>>> => {\n        const {\n            query,\n            header,\n            path: pathParameters,\n            contentType,\n            data,\n            fetchOptions,\n        } = options;\n\n        if (pathParameters) {\n            for (const [key, value] of Object.entries(pathParameters)) {\n                path = path.toString().replace(`{${key}}`, value) as TPath;\n            }\n        }\n\n        const url = new URL(`.${path.toString()}`, baseUrl);\n\n        if (query) {\n            for (const [key, value] of Object.entries(query)) {\n                if (!value) continue;\n\n                url.searchParams.set(key, value.toString());\n            }\n        }\n\n        const headers = new Headers();\n\n        if (defaultHeaders) {\n            let addDefaultHeaders = typeof defaultHeaders === 'function' ? await defaultHeaders() : defaultHeaders;\n\n            for (const [key, value] of Object.entries(addDefaultHeaders)) {\n                headers.set(key, value);\n            }\n        }\n\n        if (contentType) {\n            headers.set('Content-Type', contentType);\n        }\n\n        if (header) {\n            for (const [key, value] of Object.entries(header)) {\n                headers.set(key, value.toString());\n            }\n        }\n\n        const response = await fetch(url, {\n            method: method.toUpperCase(),\n            headers,\n            body: convertBody(data, contentType),\n            ...fetchOptions,\n        });\n\n        if (!response.ok) {\n            onError?.(ApiError.fromResponse(response));\n            throw ApiError.fromResponse(response);\n        }\n\n        const responseContentType = response.headers.get('content-type');\n\n        return await decodeResponse(response, responseContentType);\n    };\n};\n"],"mappings":"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","names":["options"]}