diff --git a/examples/basic-usage.ts b/examples/basic-usage.ts index b3f43c7..c805c94 100644 --- a/examples/basic-usage.ts +++ b/examples/basic-usage.ts @@ -144,12 +144,12 @@ function typeSafeExample() { const response = await api.request("POST /users", { body: userData, // Type-checked against CreateUserSchema }); - + // Access both data and metadata console.log("Created user:", response.data); console.log("Location header:", response.headers.get("location")); console.log("Status:", response.status); - + return response.data; }, @@ -214,7 +214,7 @@ async function errorHandlingExample() { const response = await api.request("GET /users/{id}", { params: { id: "123" }, }); - + console.log("User data:", response.data); console.log("Status:", response.status); console.log("Headers:", response.headers); @@ -250,16 +250,16 @@ async function rawResponseExample() { // Access raw Response for advanced operations const rawResponse = response["~raw"]; - + // Stream the response body const reader = rawResponse.body?.getReader(); - + // Check response headers const contentType = rawResponse.headers.get("content-type"); const contentLength = rawResponse.headers.get("content-length"); - + console.log(`Downloading ${contentType}, size: ${contentLength} bytes`); - + // Process stream... if (reader) { // Handle streaming... @@ -273,10 +273,10 @@ async function rawResponseExample() { } // Export usage examples -export { - basicExample, - typeSafeExample, +export { + basicExample, + typeSafeExample, advancedExample, errorHandlingExample, - rawResponseExample + rawResponseExample }; diff --git a/examples/nodejs-usage.ts b/examples/nodejs-usage.ts index 36acf23..4687c72 100644 --- a/examples/nodejs-usage.ts +++ b/examples/nodejs-usage.ts @@ -30,11 +30,11 @@ function nodeJsModernExample() { const response = await api.request("GET /users/{id}", { params: { id }, }); - + console.log("User data:", response.data); console.log("Response status:", response.status); console.log("Content-Type:", response.headers.get("content-type")); - + return response.data; }, }; @@ -46,7 +46,7 @@ function nodeJsModernExample() { async function nodeJsCustomFetchExample() { // For Node.js < 18 or custom fetch implementation const { default: nodeFetch } = await import("node-fetch"); - + const client = new TypeFetcher({ baseURL: "https://jsonplaceholder.typicode.com", fetch: nodeFetch as unknown as typeof globalThis.fetch, @@ -66,7 +66,7 @@ async function nodeJsCustomFetchExample() { const response = await api.request("GET /users/{id}", { params: { id }, }); - + return { user: response.data, status: response.status, @@ -82,7 +82,7 @@ async function nodeJsCustomFetchExample() { async function nodeJsUndiciExample() { // Using undici as fetch implementation const { fetch } = await import("undici"); - + const client = new TypeFetcher({ baseURL: "https://jsonplaceholder.typicode.com", fetch: fetch as unknown as typeof globalThis.fetch, @@ -93,13 +93,13 @@ async function nodeJsUndiciExample() { return { async getUsers() { const response = await api.request("GET /users"); - - console.log("Fetched", response.data?.length || 0, "users"); + + console.log("Fetched", (response.data as any)?.length || 0, "users"); console.log("Response headers:"); for (const [key, value] of response.headers.entries()) { console.log(` ${key}: ${value}`); } - + return response.data; }, }; diff --git a/examples/signal-and-raw-usage.ts b/examples/signal-and-raw-usage.ts index 9e94800..efad3d0 100644 --- a/examples/signal-and-raw-usage.ts +++ b/examples/signal-and-raw-usage.ts @@ -145,7 +145,7 @@ async function combinedExample() { // Check rate limiting headers directly from response const rateLimitRemaining = response.headers.get("x-ratelimit-remaining"); const rateLimitReset = response.headers.get("x-ratelimit-reset"); - + console.log("Rate limit remaining:", rateLimitRemaining); if (rateLimitReset) { const resetDate = new Date(parseInt(rateLimitReset) * 1000); @@ -200,7 +200,7 @@ async function longPollingExample() { try { console.log("Starting long polling for events..."); - + const response = await api.request("GET /events", { query: { timeout: "30", // Server-side timeout @@ -220,7 +220,7 @@ async function longPollingExample() { console.log("Connection:", connection); } catch (error) { clearTimeout(cancelTimeout); - + if (error instanceof Error && error.name === "AbortError") { console.log("Long polling was cancelled"); } else { @@ -265,7 +265,7 @@ async function typeInferenceExample() { // Raw response access also available: console.log("Raw response status:", response["~raw"].status); // number - + // Clean separation of data and metadata const { data, status, headers, url, "~raw": rawResponse } = response; console.log("Post data:", data); // { id: number, title: string, body: string, userId: number } diff --git a/examples/valibot-usage.ts b/examples/valibot-usage.ts index b836161..024dab0 100644 --- a/examples/valibot-usage.ts +++ b/examples/valibot-usage.ts @@ -74,10 +74,10 @@ function valibotDirectExample() { const response = await api.request("POST /users", { body: userData, }); - + console.log("Created user with status:", response.status); console.log("Location header:", response.headers.get("location")); - + return response.data; }, @@ -86,7 +86,7 @@ function valibotDirectExample() { params: { id }, body: userData, }); - + return { user: response.data, status: response.status, diff --git a/package.json b/package.json index 86d0637..b37e22a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@tknf/typefetcher", - "version": "1.0.0", + "version": "1.0.1", "description": "TypeScript-first API client with Standard Schema support, providing excellent DX and strict type safety.", "keywords": [ "typescript", diff --git a/src/client.ts b/src/client.ts index 48521d9..fc6e7f4 100644 --- a/src/client.ts +++ b/src/client.ts @@ -88,7 +88,7 @@ type ResponseForEndpoint< * TypeScript-first API client with Standard Schema support * Provides type-safe HTTP requests with runtime validation */ -export class TypeFetcher> { +export class TypeFetcher> { private endpoints: T; private config: TypeFetcherConfig; private fetch: typeof globalThis.fetch; @@ -112,20 +112,21 @@ export class TypeFetcher> { path: Path, schema?: Schema ): TypeFetcher>> { - const key = `${method} ${path}` as const; + const key = `${method} ${path}` as `${Method} ${Path}`; const newEndpoints = { ...this.endpoints, [key]: { method, path, schema, - }, + } as EndpointDefinition, } as T & Record<`${Method} ${Path}`, EndpointDefinition>; const newFetcher = new TypeFetcher< T & Record<`${Method} ${Path}`, EndpointDefinition> >(this.config); newFetcher.endpoints = newEndpoints; + newFetcher.fetch = this.fetch; return newFetcher; } @@ -133,7 +134,7 @@ export class TypeFetcher> { * Execute a request to a registered endpoint * Validates request parameters and response data if schemas are provided */ - async request( + async request( key: K, options?: RequestOptionsForEndpoint ): Promise> {