Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 11 additions & 11 deletions examples/basic-usage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
},

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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...
Expand All @@ -273,10 +273,10 @@ async function rawResponseExample() {
}

// Export usage examples
export {
basicExample,
typeSafeExample,
export {
basicExample,
typeSafeExample,
advancedExample,
errorHandlingExample,
rawResponseExample
rawResponseExample
};
16 changes: 8 additions & 8 deletions examples/nodejs-usage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
},
};
Expand All @@ -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,
Expand All @@ -66,7 +66,7 @@ async function nodeJsCustomFetchExample() {
const response = await api.request("GET /users/{id}", {
params: { id },
});

return {
user: response.data,
status: response.status,
Expand All @@ -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,
Expand All @@ -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");
Comment thread
mast1ff marked this conversation as resolved.
console.log("Response headers:");
for (const [key, value] of response.headers.entries()) {
console.log(` ${key}: ${value}`);
}

return response.data;
},
};
Expand Down
8 changes: 4 additions & 4 deletions examples/signal-and-raw-usage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand All @@ -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 {
Expand Down Expand Up @@ -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 }
Expand Down
6 changes: 3 additions & 3 deletions examples/valibot-usage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
},

Expand All @@ -86,7 +86,7 @@ function valibotDirectExample() {
params: { id },
body: userData,
});

return {
user: response.data,
status: response.status,
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -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",
Expand Down
9 changes: 5 additions & 4 deletions src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<T extends EndpointMap = Record<string, never>> {
export class TypeFetcher<T extends EndpointMap = Record<never, never>> {
private endpoints: T;
private config: TypeFetcherConfig;
private fetch: typeof globalThis.fetch;
Expand All @@ -112,28 +112,29 @@ export class TypeFetcher<T extends EndpointMap = Record<string, never>> {
path: Path,
schema?: Schema
): TypeFetcher<T & Record<`${Method} ${Path}`, EndpointDefinition<Method, Path, Schema>>> {
const key = `${method} ${path}` as const;
const key = `${method} ${path}` as `${Method} ${Path}`;
const newEndpoints = {
...this.endpoints,
[key]: {
method,
path,
schema,
},
} as EndpointDefinition<Method, Path, Schema>,
Comment thread
mast1ff marked this conversation as resolved.
} as T & Record<`${Method} ${Path}`, EndpointDefinition<Method, Path, Schema>>;

const newFetcher = new TypeFetcher<
T & Record<`${Method} ${Path}`, EndpointDefinition<Method, Path, Schema>>
>(this.config);
newFetcher.endpoints = newEndpoints;
newFetcher.fetch = this.fetch;
return newFetcher;
}

/**
* Execute a request to a registered endpoint
* Validates request parameters and response data if schemas are provided
*/
async request<K extends string & keyof T>(
async request<K extends keyof T>(
key: K,
options?: RequestOptionsForEndpoint<T, K>
): Promise<ResponseForEndpoint<T, K>> {
Expand Down