@cushin/api-runtime 5.0.7 → 5.0.8

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.
@@ -15,9 +15,10 @@ var AuthError = class extends APIError {
15
15
  }
16
16
  };
17
17
  var APIClient = class {
18
- constructor(config, authCallbacks) {
18
+ constructor(config, authCallbacks, globalHeaders) {
19
19
  this.config = config;
20
20
  this.authCallbacks = authCallbacks;
21
+ this.globalHeaders = globalHeaders || {};
21
22
  this.hooks = {
22
23
  beforeRequest: [
23
24
  async (request) => {
@@ -82,6 +83,7 @@ var APIClient = class {
82
83
  isRefreshing = false;
83
84
  refreshPromise = null;
84
85
  hooks;
86
+ globalHeaders;
85
87
  async refreshTokens() {
86
88
  if (!this.authCallbacks) {
87
89
  throw new AuthError("No auth callbacks provided");
@@ -156,6 +158,13 @@ var APIClient = class {
156
158
  }
157
159
  });
158
160
  }
161
+ if (this.globalHeaders) {
162
+ Object.entries(this.globalHeaders).forEach(([key, value]) => {
163
+ if (value !== void 0 && value !== null) {
164
+ options.headers[key] = value;
165
+ }
166
+ });
167
+ }
159
168
  if (query && Object.keys(query).length > 0) {
160
169
  const searchParams = new URLSearchParams();
161
170
  Object.entries(query).forEach(([key, value]) => {
@@ -278,8 +287,8 @@ var APIClient = class {
278
287
  return methods;
279
288
  }
280
289
  };
281
- function createAPIClient(config, authCallbacks) {
282
- const instance = new APIClient(config, authCallbacks);
290
+ function createAPIClient(config, authCallbacks, globalHeaders) {
291
+ const instance = new APIClient(config, authCallbacks, globalHeaders);
283
292
  const methods = instance.generateMethods();
284
293
  return {
285
294
  ...methods,
@@ -294,4 +303,4 @@ export {
294
303
  APIClient,
295
304
  createAPIClient
296
305
  };
297
- //# sourceMappingURL=chunk-SCPRYSBV.js.map
306
+ //# sourceMappingURL=chunk-65K2MKFS.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/client.ts"],"sourcesContent":["import ky, { HTTPError } from \"ky\";\nimport type { APIConfig, APIEndpoint } from \"./schema.js\";\n\nexport interface AuthTokens {\n accessToken: string;\n refreshToken?: string;\n}\n\nexport interface AuthCallbacks {\n getTokens: () => Promise<AuthTokens | null>;\n onAuthError?: () => void;\n onRefreshToken?: () => Promise<void>;\n}\n\nexport class APIError extends Error {\n constructor(\n message: string,\n public status: number,\n public response?: any,\n ) {\n super(message);\n this.name = \"APIError\";\n }\n}\n\nexport class AuthError extends APIError {\n constructor(message: string = \"Authentication failed\") {\n super(message, 401);\n this.name = \"AuthError\";\n }\n}\n\nexport class APIClient {\n private client: typeof ky;\n private isRefreshing = false;\n private refreshPromise: Promise<void> | null = null;\n private hooks: any;\n private globalHeaders: Record<string, string>;\n\n constructor(\n private config: APIConfig,\n private authCallbacks?: AuthCallbacks,\n globalHeaders?: Record<string, string>,\n ) {\n this.globalHeaders = globalHeaders || {};\n this.hooks = {\n beforeRequest: [\n async (request: Request) => {\n const tokens = await this.authCallbacks?.getTokens();\n if (tokens?.accessToken) {\n request.headers.set(\n \"Authorization\",\n `Bearer ${tokens.accessToken}`,\n );\n }\n },\n ],\n beforeRetry: [\n async ({ request, error, retryCount }: any) => {\n if (error instanceof HTTPError && error.response.status === 401) {\n if (retryCount === 1 && this.authCallbacks) {\n try {\n await this.refreshTokens();\n const tokens = await this.authCallbacks.getTokens();\n if (tokens?.accessToken) {\n request.headers.set(\n \"Authorization\",\n `Bearer ${tokens.accessToken}`,\n );\n }\n } catch (refreshError) {\n this.authCallbacks.onAuthError?.();\n throw new AuthError();\n }\n } else {\n this.authCallbacks?.onAuthError?.();\n throw new AuthError();\n }\n }\n },\n ],\n beforeError: [\n async (error: any) => {\n const { response } = error;\n if (response?.body) {\n try {\n const body = await response.json();\n error.message =\n (body as Error).message || `HTTP ${response.status}`;\n } catch {\n // Keep original message\n }\n }\n return error;\n },\n ],\n };\n\n this.client = ky.create({\n prefixUrl: this.config.baseUrl,\n retry: {\n limit: 2,\n methods: [\"get\", \"post\", \"put\", \"delete\", \"patch\"],\n statusCodes: [401],\n },\n hooks: this.hooks,\n });\n }\n\n private async refreshTokens(): Promise<void> {\n if (!this.authCallbacks) {\n throw new AuthError(\"No auth callbacks provided\");\n }\n\n if (this.isRefreshing && this.refreshPromise) {\n return this.refreshPromise;\n }\n\n this.isRefreshing = true;\n\n this.refreshPromise = (async () => {\n try {\n if (this.authCallbacks?.onRefreshToken) {\n await this.authCallbacks.onRefreshToken();\n } else {\n throw new AuthError(\"No refresh token handler provided\");\n }\n } catch (error) {\n throw error;\n } finally {\n this.isRefreshing = false;\n this.refreshPromise = null;\n }\n })();\n\n return this.refreshPromise;\n }\n\n private buildPath(path: string, params?: Record<string, any>): string {\n let finalPath = path;\n\n // Replace path parameters if provided\n if (params) {\n Object.entries(params).forEach(([key, value]) => {\n finalPath = finalPath.replace(\n `:${key}`,\n encodeURIComponent(String(value)),\n );\n });\n }\n\n // Remove leading slash for ky prefixUrl compatibility\n if (finalPath.startsWith('/')) {\n finalPath = finalPath.slice(1);\n }\n\n return finalPath;\n }\n\n private getEndpointBaseUrl(endpoint: APIEndpoint): string {\n return endpoint.baseUrl || this.config.baseUrl!;\n }\n\n private getClientForEndpoint(endpoint: APIEndpoint): typeof ky {\n const endpointBaseUrl = this.getEndpointBaseUrl(endpoint);\n\n if (endpointBaseUrl === this.config.baseUrl) {\n return this.client;\n }\n\n return ky.create({\n prefixUrl: endpointBaseUrl,\n retry: {\n limit: 2,\n methods: [\"get\", \"post\", \"put\", \"delete\", \"patch\"],\n statusCodes: [401],\n },\n hooks: this.hooks,\n });\n }\n\n async request<T>(\n endpoint: APIEndpoint,\n params?: Record<string, any>,\n query?: Record<string, any>,\n body?: any,\n requestHeaders?: Record<string, string>,\n ): Promise<T> {\n try {\n const path = this.buildPath(endpoint.path, params);\n const client = this.getClientForEndpoint(endpoint);\n\n const options: Record<string, any> = {\n method: endpoint.method,\n headers: {\n \"Accept-Encoding\": this.config.acceptEncoding || \"gzip, deflate, br\",\n },\n };\n\n // Apply global headers from config first\n if (this.config.headers) {\n Object.entries(this.config.headers).forEach(([key, value]) => {\n if (value !== undefined && value !== null) {\n options.headers[key] = value;\n }\n });\n }\n\n // Apply runtime global headers (higher priority than config headers)\n if (this.globalHeaders) {\n Object.entries(this.globalHeaders).forEach(([key, value]) => {\n if (value !== undefined && value !== null) {\n options.headers[key] = value;\n }\n });\n }\n\n if (query && Object.keys(query).length > 0) {\n const searchParams = new URLSearchParams();\n Object.entries(query).forEach(([key, value]) => {\n if (value !== undefined && value !== null) {\n searchParams.append(key, String(value));\n }\n });\n if (searchParams.toString()) {\n options.searchParams = searchParams;\n }\n }\n\n // Track if body is FormData to prevent Content-Type override\n const isFormData = body instanceof FormData;\n\n // Handle body and set appropriate Content-Type\n if (body && endpoint.method !== \"GET\") {\n // Check if body is FormData\n if (isFormData) {\n options.body = body;\n // DO NOT set Content-Type for FormData\n // Browser/HTTP client will automatically set multipart/form-data with boundary\n } else if (endpoint.body) {\n const validatedBody = endpoint.body.parse(body);\n options.json = validatedBody;\n // ky automatically sets Content-Type: application/json when using options.json\n } else {\n options.json = body;\n // ky automatically sets Content-Type: application/json when using options.json\n }\n }\n // Do not set Content-Type for GET requests or requests without body\n\n // Apply custom headers AFTER body processing\n // IMPORTANT: Never override Content-Type for FormData\n if (endpoint.headers) {\n Object.entries(endpoint.headers).forEach(([key, value]) => {\n // Skip Content-Type header if body is FormData\n if (\n isFormData &&\n key.toLowerCase() === \"content-type\"\n ) {\n // Ignore Content-Type header for FormData to prevent boundary issues\n return;\n }\n\n if (value !== undefined && value !== null) {\n options.headers[key] = value;\n } else if (value === undefined || value === null) {\n // Allow explicitly unsetting headers\n delete options.headers[key];\n }\n });\n }\n\n // Apply request-level headers (highest priority)\n if (requestHeaders) {\n Object.entries(requestHeaders).forEach(([key, value]) => {\n // Skip Content-Type header if body is FormData\n if (\n isFormData &&\n key.toLowerCase() === \"content-type\"\n ) {\n // Ignore Content-Type header for FormData to prevent boundary issues\n return;\n }\n\n if (value !== undefined && value !== null) {\n options.headers[key] = value;\n }\n });\n }\n\n const response = await client(path, options);\n\n // Check if response has content before parsing JSON\n const contentLength = response.headers.get('content-length');\n const contentType = response.headers.get('content-type');\n\n // Handle empty responses (204 No Content, or Content-Length: 0)\n if (\n response.status === 204 ||\n contentLength === '0' ||\n (!contentType?.includes('application/json') && !response.body)\n ) {\n const emptyResult = {} as T;\n if (endpoint.response) {\n return endpoint.response.parse(emptyResult);\n }\n return emptyResult;\n }\n\n // Parse JSON response\n const data = await response.json();\n\n if (endpoint.response) {\n return endpoint.response.parse(data);\n }\n\n return data as T;\n } catch (error) {\n if (error instanceof HTTPError) {\n const errorData = await error.response.json().catch(() => ({}));\n throw new APIError(\n errorData.message || error.message,\n error.response.status,\n errorData,\n );\n }\n\n if (error instanceof AuthError) {\n throw error;\n }\n\n throw new APIError(\n error instanceof Error ? error.message : \"Network error\",\n 0,\n );\n }\n }\n\n updateAuthCallbacks(authCallbacks: AuthCallbacks) {\n this.authCallbacks = authCallbacks;\n }\n\n async refreshAuth(): Promise<void> {\n if (!this.authCallbacks) {\n throw new AuthError(\"No auth callbacks provided\");\n }\n await this.refreshTokens();\n }\n\n generateMethods() {\n const methods: any = {};\n\n Object.entries(this.config.endpoints).forEach(([name, endpoint]) => {\n if (endpoint.method === \"GET\") {\n if (endpoint.params && endpoint.query) {\n methods[name] = (params: any, query?: any, headers?: Record<string, string>): Promise<any> => {\n return this.request(endpoint, params, query, undefined, headers);\n };\n } else if (endpoint.params) {\n methods[name] = (params: any, headers?: Record<string, string>): Promise<any> => {\n return this.request(endpoint, params, undefined, undefined, headers);\n };\n } else if (endpoint.query) {\n methods[name] = (query?: any, headers?: Record<string, string>): Promise<any> => {\n return this.request(endpoint, undefined, query, undefined, headers);\n };\n } else {\n methods[name] = (headers?: Record<string, string>): Promise<any> => {\n return this.request(endpoint, undefined, undefined, undefined, headers);\n };\n }\n } else {\n // For non-GET methods (POST, PUT, PATCH, DELETE)\n // Always support body parameter to allow FormData and other dynamic bodies\n if (endpoint.params) {\n methods[name] = (params: any, body?: any, headers?: Record<string, string>): Promise<any> => {\n return this.request(endpoint, params, undefined, body, headers);\n };\n } else {\n // Always allow optional body parameter for non-GET methods\n methods[name] = (body?: any, headers?: Record<string, string>): Promise<any> => {\n return this.request(endpoint, undefined, undefined, body, headers);\n };\n }\n }\n });\n\n return methods;\n }\n}\n\nexport function createAPIClient(\n config: APIConfig,\n authCallbacks?: AuthCallbacks,\n globalHeaders?: Record<string, string>,\n) {\n const instance = new APIClient(config, authCallbacks, globalHeaders);\n const methods = instance.generateMethods();\n\n return {\n ...methods,\n refreshAuth: () => instance.refreshAuth(),\n updateAuthCallbacks: (newCallbacks: AuthCallbacks) =>\n instance.updateAuthCallbacks(newCallbacks),\n };\n}\n"],"mappings":"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","names":[]}
package/dist/client.d.ts CHANGED
@@ -25,7 +25,8 @@ declare class APIClient {
25
25
  private isRefreshing;
26
26
  private refreshPromise;
27
27
  private hooks;
28
- constructor(config: APIConfig, authCallbacks?: AuthCallbacks | undefined);
28
+ private globalHeaders;
29
+ constructor(config: APIConfig, authCallbacks?: AuthCallbacks | undefined, globalHeaders?: Record<string, string>);
29
30
  private refreshTokens;
30
31
  private buildPath;
31
32
  private getEndpointBaseUrl;
@@ -35,6 +36,6 @@ declare class APIClient {
35
36
  refreshAuth(): Promise<void>;
36
37
  generateMethods(): any;
37
38
  }
38
- declare function createAPIClient(config: APIConfig, authCallbacks?: AuthCallbacks): any;
39
+ declare function createAPIClient(config: APIConfig, authCallbacks?: AuthCallbacks, globalHeaders?: Record<string, string>): any;
39
40
 
40
41
  export { APIClient, APIError, type AuthCallbacks, AuthError, type AuthTokens, createAPIClient };
package/dist/client.js CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  APIError,
4
4
  AuthError,
5
5
  createAPIClient
6
- } from "./chunk-SCPRYSBV.js";
6
+ } from "./chunk-65K2MKFS.js";
7
7
  export {
8
8
  APIClient,
9
9
  APIError,
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  APIError,
4
4
  AuthError,
5
5
  createAPIClient
6
- } from "./chunk-SCPRYSBV.js";
6
+ } from "./chunk-65K2MKFS.js";
7
7
  import {
8
8
  defineConfig,
9
9
  defineEndpoint,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cushin/api-runtime",
3
- "version": "5.0.7",
3
+ "version": "5.0.8",
4
4
  "description": "Runtime utilities for Cushin API codegen - types, schemas, and HTTP client",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/client.ts"],"sourcesContent":["import ky, { HTTPError } from \"ky\";\nimport type { APIConfig, APIEndpoint } from \"./schema.js\";\n\nexport interface AuthTokens {\n accessToken: string;\n refreshToken?: string;\n}\n\nexport interface AuthCallbacks {\n getTokens: () => Promise<AuthTokens | null>;\n onAuthError?: () => void;\n onRefreshToken?: () => Promise<void>;\n}\n\nexport class APIError extends Error {\n constructor(\n message: string,\n public status: number,\n public response?: any,\n ) {\n super(message);\n this.name = \"APIError\";\n }\n}\n\nexport class AuthError extends APIError {\n constructor(message: string = \"Authentication failed\") {\n super(message, 401);\n this.name = \"AuthError\";\n }\n}\n\nexport class APIClient {\n private client: typeof ky;\n private isRefreshing = false;\n private refreshPromise: Promise<void> | null = null;\n private hooks: any;\n\n constructor(\n private config: APIConfig,\n private authCallbacks?: AuthCallbacks,\n ) {\n this.hooks = {\n beforeRequest: [\n async (request: Request) => {\n const tokens = await this.authCallbacks?.getTokens();\n if (tokens?.accessToken) {\n request.headers.set(\n \"Authorization\",\n `Bearer ${tokens.accessToken}`,\n );\n }\n },\n ],\n beforeRetry: [\n async ({ request, error, retryCount }: any) => {\n if (error instanceof HTTPError && error.response.status === 401) {\n if (retryCount === 1 && this.authCallbacks) {\n try {\n await this.refreshTokens();\n const tokens = await this.authCallbacks.getTokens();\n if (tokens?.accessToken) {\n request.headers.set(\n \"Authorization\",\n `Bearer ${tokens.accessToken}`,\n );\n }\n } catch (refreshError) {\n this.authCallbacks.onAuthError?.();\n throw new AuthError();\n }\n } else {\n this.authCallbacks?.onAuthError?.();\n throw new AuthError();\n }\n }\n },\n ],\n beforeError: [\n async (error: any) => {\n const { response } = error;\n if (response?.body) {\n try {\n const body = await response.json();\n error.message =\n (body as Error).message || `HTTP ${response.status}`;\n } catch {\n // Keep original message\n }\n }\n return error;\n },\n ],\n };\n\n this.client = ky.create({\n prefixUrl: this.config.baseUrl,\n retry: {\n limit: 2,\n methods: [\"get\", \"post\", \"put\", \"delete\", \"patch\"],\n statusCodes: [401],\n },\n hooks: this.hooks,\n });\n }\n\n private async refreshTokens(): Promise<void> {\n if (!this.authCallbacks) {\n throw new AuthError(\"No auth callbacks provided\");\n }\n\n if (this.isRefreshing && this.refreshPromise) {\n return this.refreshPromise;\n }\n\n this.isRefreshing = true;\n\n this.refreshPromise = (async () => {\n try {\n if (this.authCallbacks?.onRefreshToken) {\n await this.authCallbacks.onRefreshToken();\n } else {\n throw new AuthError(\"No refresh token handler provided\");\n }\n } catch (error) {\n throw error;\n } finally {\n this.isRefreshing = false;\n this.refreshPromise = null;\n }\n })();\n\n return this.refreshPromise;\n }\n\n private buildPath(path: string, params?: Record<string, any>): string {\n let finalPath = path;\n\n // Replace path parameters if provided\n if (params) {\n Object.entries(params).forEach(([key, value]) => {\n finalPath = finalPath.replace(\n `:${key}`,\n encodeURIComponent(String(value)),\n );\n });\n }\n\n // Remove leading slash for ky prefixUrl compatibility\n if (finalPath.startsWith('/')) {\n finalPath = finalPath.slice(1);\n }\n\n return finalPath;\n }\n\n private getEndpointBaseUrl(endpoint: APIEndpoint): string {\n return endpoint.baseUrl || this.config.baseUrl!;\n }\n\n private getClientForEndpoint(endpoint: APIEndpoint): typeof ky {\n const endpointBaseUrl = this.getEndpointBaseUrl(endpoint);\n\n if (endpointBaseUrl === this.config.baseUrl) {\n return this.client;\n }\n\n return ky.create({\n prefixUrl: endpointBaseUrl,\n retry: {\n limit: 2,\n methods: [\"get\", \"post\", \"put\", \"delete\", \"patch\"],\n statusCodes: [401],\n },\n hooks: this.hooks,\n });\n }\n\n async request<T>(\n endpoint: APIEndpoint,\n params?: Record<string, any>,\n query?: Record<string, any>,\n body?: any,\n requestHeaders?: Record<string, string>,\n ): Promise<T> {\n try {\n const path = this.buildPath(endpoint.path, params);\n const client = this.getClientForEndpoint(endpoint);\n\n const options: Record<string, any> = {\n method: endpoint.method,\n headers: {\n \"Accept-Encoding\": this.config.acceptEncoding || \"gzip, deflate, br\",\n },\n };\n\n // Apply global headers from config first\n if (this.config.headers) {\n Object.entries(this.config.headers).forEach(([key, value]) => {\n if (value !== undefined && value !== null) {\n options.headers[key] = value;\n }\n });\n }\n\n if (query && Object.keys(query).length > 0) {\n const searchParams = new URLSearchParams();\n Object.entries(query).forEach(([key, value]) => {\n if (value !== undefined && value !== null) {\n searchParams.append(key, String(value));\n }\n });\n if (searchParams.toString()) {\n options.searchParams = searchParams;\n }\n }\n\n // Track if body is FormData to prevent Content-Type override\n const isFormData = body instanceof FormData;\n\n // Handle body and set appropriate Content-Type\n if (body && endpoint.method !== \"GET\") {\n // Check if body is FormData\n if (isFormData) {\n options.body = body;\n // DO NOT set Content-Type for FormData\n // Browser/HTTP client will automatically set multipart/form-data with boundary\n } else if (endpoint.body) {\n const validatedBody = endpoint.body.parse(body);\n options.json = validatedBody;\n // ky automatically sets Content-Type: application/json when using options.json\n } else {\n options.json = body;\n // ky automatically sets Content-Type: application/json when using options.json\n }\n }\n // Do not set Content-Type for GET requests or requests without body\n\n // Apply custom headers AFTER body processing\n // IMPORTANT: Never override Content-Type for FormData\n if (endpoint.headers) {\n Object.entries(endpoint.headers).forEach(([key, value]) => {\n // Skip Content-Type header if body is FormData\n if (\n isFormData &&\n key.toLowerCase() === \"content-type\"\n ) {\n // Ignore Content-Type header for FormData to prevent boundary issues\n return;\n }\n\n if (value !== undefined && value !== null) {\n options.headers[key] = value;\n } else if (value === undefined || value === null) {\n // Allow explicitly unsetting headers\n delete options.headers[key];\n }\n });\n }\n\n // Apply request-level headers (highest priority)\n if (requestHeaders) {\n Object.entries(requestHeaders).forEach(([key, value]) => {\n // Skip Content-Type header if body is FormData\n if (\n isFormData &&\n key.toLowerCase() === \"content-type\"\n ) {\n // Ignore Content-Type header for FormData to prevent boundary issues\n return;\n }\n\n if (value !== undefined && value !== null) {\n options.headers[key] = value;\n }\n });\n }\n\n const response = await client(path, options);\n\n // Check if response has content before parsing JSON\n const contentLength = response.headers.get('content-length');\n const contentType = response.headers.get('content-type');\n\n // Handle empty responses (204 No Content, or Content-Length: 0)\n if (\n response.status === 204 ||\n contentLength === '0' ||\n (!contentType?.includes('application/json') && !response.body)\n ) {\n const emptyResult = {} as T;\n if (endpoint.response) {\n return endpoint.response.parse(emptyResult);\n }\n return emptyResult;\n }\n\n // Parse JSON response\n const data = await response.json();\n\n if (endpoint.response) {\n return endpoint.response.parse(data);\n }\n\n return data as T;\n } catch (error) {\n if (error instanceof HTTPError) {\n const errorData = await error.response.json().catch(() => ({}));\n throw new APIError(\n errorData.message || error.message,\n error.response.status,\n errorData,\n );\n }\n\n if (error instanceof AuthError) {\n throw error;\n }\n\n throw new APIError(\n error instanceof Error ? error.message : \"Network error\",\n 0,\n );\n }\n }\n\n updateAuthCallbacks(authCallbacks: AuthCallbacks) {\n this.authCallbacks = authCallbacks;\n }\n\n async refreshAuth(): Promise<void> {\n if (!this.authCallbacks) {\n throw new AuthError(\"No auth callbacks provided\");\n }\n await this.refreshTokens();\n }\n\n generateMethods() {\n const methods: any = {};\n\n Object.entries(this.config.endpoints).forEach(([name, endpoint]) => {\n if (endpoint.method === \"GET\") {\n if (endpoint.params && endpoint.query) {\n methods[name] = (params: any, query?: any, headers?: Record<string, string>): Promise<any> => {\n return this.request(endpoint, params, query, undefined, headers);\n };\n } else if (endpoint.params) {\n methods[name] = (params: any, headers?: Record<string, string>): Promise<any> => {\n return this.request(endpoint, params, undefined, undefined, headers);\n };\n } else if (endpoint.query) {\n methods[name] = (query?: any, headers?: Record<string, string>): Promise<any> => {\n return this.request(endpoint, undefined, query, undefined, headers);\n };\n } else {\n methods[name] = (headers?: Record<string, string>): Promise<any> => {\n return this.request(endpoint, undefined, undefined, undefined, headers);\n };\n }\n } else {\n // For non-GET methods (POST, PUT, PATCH, DELETE)\n // Always support body parameter to allow FormData and other dynamic bodies\n if (endpoint.params) {\n methods[name] = (params: any, body?: any, headers?: Record<string, string>): Promise<any> => {\n return this.request(endpoint, params, undefined, body, headers);\n };\n } else {\n // Always allow optional body parameter for non-GET methods\n methods[name] = (body?: any, headers?: Record<string, string>): Promise<any> => {\n return this.request(endpoint, undefined, undefined, body, headers);\n };\n }\n }\n });\n\n return methods;\n }\n}\n\nexport function createAPIClient(\n config: APIConfig,\n authCallbacks?: AuthCallbacks,\n) {\n const instance = new APIClient(config, authCallbacks);\n const methods = instance.generateMethods();\n\n return {\n ...methods,\n refreshAuth: () => instance.refreshAuth(),\n updateAuthCallbacks: (newCallbacks: AuthCallbacks) =>\n instance.updateAuthCallbacks(newCallbacks),\n };\n}\n"],"mappings":"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","names":[]}