UNPKG

kitcn

Version:

kitcn - React Query integration and CLI tools for Convex

169 lines (164 loc) 6.32 kB
import { a as isCRPCErrorCode, i as isCRPCError, n as defaultIsUnauthorized, r as isCRPCClientError, t as CRPCClientError } from "../error-Bvo7YEhk.js"; import { a as defaultCRPCTransformer, c as identityTransformer, i as decodeWire, n as createTaggedTransformer, o as encodeWire, r as dateWireCodec, s as getTransformer, t as DATE_CODEC_TAG } from "../transformer-C6pGVHqx.js"; import { n as convexInfiniteQueryOptions, r as convexQuery, t as convexAction } from "../query-options-C96zLANM.js"; //#region src/crpc/auth-error.ts /** * Auth Mutation Error * * Framework-agnostic error class for Better Auth mutations. */ /** * Error thrown when a Better Auth mutation fails. * Contains the original error details from Better Auth. */ var AuthMutationError = class extends Error { /** Error code from Better Auth (e.g., 'INVALID_PASSWORD', 'EMAIL_ALREADY_REGISTERED') */ code; /** HTTP status code */ status; /** HTTP status text */ statusText; constructor(authError) { super(authError.message || authError.statusText); this.name = "AuthMutationError"; this.code = authError.code; this.status = authError.status; this.statusText = authError.statusText; } }; /** * Type guard to check if an error is an AuthMutationError. */ function isAuthMutationError(error) { return error instanceof AuthMutationError; } //#endregion //#region src/crpc/http-types.ts /** HTTP client error */ var HttpClientError = class extends Error { name = "HttpClientError"; code; status; procedureName; constructor(opts) { super(opts.message ?? `${opts.code}: ${opts.procedureName}`); this.code = opts.code; this.status = opts.status; this.procedureName = opts.procedureName; } }; /** Type guard for HttpClientError */ const isHttpClientError = (error) => error instanceof HttpClientError; //#endregion //#region src/crpc/http-client.ts /** * HTTP Client Helpers * * Framework-agnostic utilities for executing HTTP requests * against Convex HTTP endpoints. */ /** Reserved keys that are not part of JSON body */ const RESERVED_KEYS = new Set([ "params", "searchParams", "form", "fetch", "init", "headers" ]); /** * Replace URL path parameters with actual values. * e.g., '/users/:id' with { id: '123' } -> '/users/123' */ function replaceUrlParam(url, params) { return url.replace(/:(\w+)/g, (_, key) => { const value = params[key]; return value !== void 0 ? encodeURIComponent(value) : `:${key}`; }); } /** * Build URLSearchParams from query object. * Handles array values as multiple params with same key (like Hono). */ function buildSearchParams(query) { const params = new URLSearchParams(); for (const [key, value] of Object.entries(query)) if (Array.isArray(value)) for (const v of value) params.append(key, v); else if (value !== void 0 && value !== null) params.append(key, value); return params; } /** * Hono-style HTTP request executor. * Processes args in the same way as Hono's ClientRequestImpl.fetch(). */ async function executeHttpRequest(opts) { const { method, path } = opts.route; const args = opts.args ?? {}; let rBody; let cType; if (args.form) { const form = new FormData(); for (const [k, v] of Object.entries(args.form)) if (Array.isArray(v)) for (const v2 of v) form.append(k, v2); else form.append(k, v); rBody = form; } else { const jsonBody = {}; for (const [key, value] of Object.entries(args)) if (!RESERVED_KEYS.has(key) && value !== void 0) jsonBody[key] = value; if (Object.keys(jsonBody).length > 0) { rBody = JSON.stringify(opts.transformer.input.serialize(jsonBody)); cType = "application/json"; } } const argsClientOpts = {}; if (args.fetch) argsClientOpts.fetch = args.fetch; if (args.init) argsClientOpts.init = args.init; if (args.headers) argsClientOpts.headers = args.headers; const mergedClientOpts = { ...opts.clientOpts, ...argsClientOpts }; const resolvedBaseHeaders = typeof opts.baseHeaders === "function" ? await opts.baseHeaders() : opts.baseHeaders; const headerValues = { ...typeof mergedClientOpts.headers === "function" ? await mergedClientOpts.headers() : mergedClientOpts.headers }; if (cType) headerValues["Content-Type"] = cType; const finalHeaders = {}; if (resolvedBaseHeaders) { for (const [key, value] of Object.entries(resolvedBaseHeaders)) if (value !== void 0) finalHeaders[key] = value; } Object.assign(finalHeaders, headerValues); let url = opts.convexSiteUrl + path; if (args.params) url = opts.convexSiteUrl + replaceUrlParam(path, args.params); if (args.searchParams) { const queryString = buildSearchParams(args.searchParams).toString(); if (queryString) url = `${url}?${queryString}`; } const methodUpperCase = method.toUpperCase(); const setBody = !(methodUpperCase === "GET" || methodUpperCase === "HEAD"); const response = await (mergedClientOpts.fetch ?? opts.baseFetch ?? globalThis.fetch)(url, { body: setBody ? rBody : void 0, method: methodUpperCase, headers: finalHeaders, ...mergedClientOpts.init }); if (!response.ok) { const errorData = await response.json().catch(() => ({ error: { code: "UNKNOWN", message: response.statusText } })); const errorCode = errorData?.error?.code || "UNKNOWN"; const errorMessage = errorData?.error?.message || response.statusText; throw new HttpClientError({ code: errorCode, status: response.status, procedureName: opts.procedureName, message: errorMessage }); } if (response.headers.get("content-length") === "0" || response.status === 204) return; if ((response.headers.get("content-type") || "").includes("application/json")) return opts.transformer.output.deserialize(await response.json()); return response.text(); } //#endregion //#region src/crpc/types.ts /** Symbol key for attaching FunctionReference to options (non-serializable) */ const FUNC_REF_SYMBOL = Symbol.for("convex.funcRef"); //#endregion export { AuthMutationError, CRPCClientError, DATE_CODEC_TAG, FUNC_REF_SYMBOL, HttpClientError, RESERVED_KEYS, buildSearchParams, convexAction, convexInfiniteQueryOptions, convexQuery, createTaggedTransformer, dateWireCodec, decodeWire, defaultCRPCTransformer, defaultIsUnauthorized, encodeWire, executeHttpRequest, getTransformer, identityTransformer, isAuthMutationError, isCRPCClientError, isCRPCError, isCRPCErrorCode, isHttpClientError, replaceUrlParam };