### Basic Hook-Fetch Usage: Simple and Instance-Based Requests Source: https://github.com/jsonlee12138/hook-fetch/blob/main/apps/docs/i18n/en/docusaurus-plugin-content-docs/current/getting-started.md Demonstrates making simple GET and POST requests using hook-fetch directly, and then shows how to create a configured instance for managing baseURL, headers, and timeouts. The instance-based approach is recommended for better configuration management. ```typescript import hookFetch from 'hook-fetch'; // GET request const response = await hookFetch('https://jsonplaceholder.typicode.com/posts/1').json(); console.log(response); // POST request const newPost = await hookFetch('https://jsonplaceholder.typicode.com/posts', { method: 'POST', data: { title: 'My New Post', body: 'This is the content of my post', userId: 1 } }).json(); // Creating an Instance const api = hookFetch.create({ baseURL: 'https://jsonplaceholder.typicode.com', headers: { 'Content-Type': 'application/json' }, timeout: 5000 // 5 seconds timeout }); // Use the instance const posts = await api.get('/posts').json(); const users = await api.get('/users').json(); ``` -------------------------------- ### Hook-Fetch HTTP Methods: GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS Source: https://github.com/jsonlee12138/hook-fetch/blob/main/apps/docs/i18n/en/docusaurus-plugin-content-docs/current/getting-started.md Illustrates the usage of various HTTP methods supported by Hook-Fetch, including GET with and without query parameters, POST, PUT, PATCH, DELETE, HEAD for retrieving headers, and OPTIONS for checking allowed methods. These methods are typically called on a Hook-Fetch instance. ```typescript const api = hookFetch.create({ baseURL: 'https://jsonplaceholder.typicode.com' }); // GET Requests // Without parameters const posts = await api.get('/posts').json(); // With query parameters const filteredPosts = await api.get('/posts', { userId: 1, _limit: 10 }).json(); // POST Requests const newPost = await api.post('/posts', { title: 'New Post', body: 'Post content', userId: 1 }).json(); // PUT Requests const updatedPost = await api.put('/posts/1', { id: 1, title: 'Updated Post', body: 'Updated content', userId: 1 }).json(); // PATCH Requests const patchedPost = await api.patch('/posts/1', { title: 'Patched Title' }).json(); // DELETE Requests const result = await api.delete('/posts/1').json(); // HEAD and OPTIONS Requests // HEAD request - get only response headers const headResponse = await api.head('/posts/1'); console.log(headResponse.headers); // OPTIONS request - get allowed methods const optionsResponse = await api.options('/posts'); ``` -------------------------------- ### Install Hook-Fetch via npm, yarn, pnpm Source: https://github.com/jsonlee12138/hook-fetch/blob/main/apps/docs/i18n/en/docusaurus-plugin-content-docs/current/reference/faq.md Provides installation instructions for Hook-Fetch using different package managers: npm, yarn, and pnpm. ```bash # npm npm install hook-fetch # yarn yarn add hook-fetch # pnpm pnpm add hook-fetch ``` -------------------------------- ### Hook-Fetch File Upload using the Upload Method Source: https://github.com/jsonlee12138/hook-fetch/blob/main/apps/docs/i18n/en/docusaurus-plugin-content-docs/current/getting-started.md Demonstrates how to upload files using Hook-Fetch's dedicated `upload` method. It shows how to select a file from an input element and send it along with other data in the request payload. ```typescript // Using the upload method const fileInput = document.querySelector('input[type="file"]'); const file = fileInput.files[0]; const result = await api.upload('/upload', { file: file, description: 'My uploaded file' }).json(); ``` -------------------------------- ### Install Hook-Fetch via npm, yarn, or pnpm Source: https://github.com/jsonlee12138/hook-fetch/blob/main/apps/docs/i18n/en/docusaurus-plugin-content-docs/current/intro.md Instructions for installing the Hook-Fetch library using common package managers like npm, yarn, and pnpm. ```bash # Using npm npm install hook-fetch # Using yarn yarn add hook-fetch # Using pnpm pnpm add hook-fetch ``` -------------------------------- ### React: Install and Import useHookFetch Source: https://github.com/jsonlee12138/hook-fetch/blob/main/apps/docs/i18n/en/docusaurus-plugin-content-docs/current/framework-integration.md Demonstrates how to install and import the `useHookFetch` hook from the 'hook-fetch/react' package for use in React applications. It also shows importing the main `hookFetch` instance. ```typescript import { useHookFetch } from 'hook-fetch/react'; import hookFetch from 'hook-fetch'; ``` -------------------------------- ### TypeScript Type Definitions Example Source: https://github.com/jsonlee12138/hook-fetch/blob/main/apps/docs/i18n/en/docusaurus-plugin-content-docs/current/reference/faq.md Demonstrates how to use Hook-Fetch with TypeScript for type safety and IntelliSense. It shows defining an interface for user data and making a typed GET request. ```typescript interface User { id: number; name: string; email: string; } const user = await api.get('/users/1').json(); // user is fully typed as User ``` -------------------------------- ### Basic Data Fetching with hook-fetch in Vue.js Source: https://github.com/jsonlee12138/hook-fetch/blob/main/apps/docs/docs/framework-integration.md Demonstrates how to fetch user data using the useHookFetch hook from hook-fetch/vue. It shows how to create an API instance, make a GET request, handle loading states, and display fetched data. Error handling is also included. ```vue ``` -------------------------------- ### Hook-Fetch Instance Creation and Usage (JavaScript) Source: https://github.com/jsonlee12138/hook-fetch/blob/main/apps/docs/i18n/en/docusaurus-plugin-content-docs/current/api-reference.md Shows how to create a reusable instance of Hook-Fetch with a base URL and default headers. This instance can then be used to make requests, simplifying repetitive configurations. Examples include GET and POST requests using the created instance. ```javascript const api = hookFetch.create({ baseURL: 'https://api.example.com', headers: { 'Authorization': 'Bearer token' } }); const users = await api.get('/users').json(); const newUser = await api.post('/users', userData).json(); ``` -------------------------------- ### Plugin Factory Example (TypeScript) Source: https://github.com/jsonlee12138/hook-fetch/blob/main/apps/docs/i18n/en/docusaurus-plugin-content-docs/current/plugins.md Shows how to create reusable plugin factories. This example, `createApiPlugin`, composes multiple behaviors (auth, retry, cache) into a single plugin, promoting modularity and code reuse. It accepts an options object to configure the composed behaviors. ```typescript function createApiPlugin(options: ApiPluginOptions) { return { name: 'api-plugin', ...createAuthBehavior(options.auth), ...createRetryBehavior(options.retry), ...createCacheBehavior(options.cache) }; } ``` -------------------------------- ### HTTP Request Methods with Hook-Fetch Instance (TypeScript) Source: https://github.com/jsonlee12138/hook-fetch/blob/main/README.en.md Shows examples of making various HTTP requests (GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS) using a pre-configured hook-fetch instance. ```typescript // GET request const data = await api.get('/users', { page: 1, limit: 10 }).json(); // POST request const newUser = await api.post('/users', { name: 'John', age: 30 }).json(); // PUT request const updatedUser = await api.put('/users/1', { name: 'John Doe' }).json(); // PATCH request const patchedUser = await api.patch('/users/1', { age: 31 }).json(); // DELETE request const deleted = await api.delete('/users/1').json(); // HEAD request const headers = await api.head('/users/1'); // OPTIONS request const options = await api.options('/users'); ``` -------------------------------- ### Make Simple GET Request with Hook-Fetch Source: https://github.com/jsonlee12138/hook-fetch/blob/main/apps/docs/i18n/en/docusaurus-plugin-content-docs/current/reference/faq.md Illustrates how to perform a simple GET request using Hook-Fetch, including requests with query parameters. ```typescript import hookFetch from 'hook-fetch'; // Simple GET request const response = await hookFetch('https://api.example.com/users').json(); // With parameters const users = await hookFetch('https://api.example.com/users', { params: { page: 1, limit: 10 } }).json(); ``` -------------------------------- ### Basic GET and POST Requests with Hook-Fetch Source: https://github.com/jsonlee12138/hook-fetch/blob/main/apps/docs/i18n/en/docusaurus-plugin-content-docs/current/intro.md Demonstrates how to perform basic GET and POST HTTP requests using the Hook-Fetch library. It shows how to chain methods like `.json()` to parse the response body. ```typescript import hookFetch from 'hook-fetch'; // GET request const response = await hookFetch('https://api.example.com/users').json(); console.log(response); // POST request const newUser = await hookFetch('https://api.example.com/users', { method: 'POST', data: { name: 'John', email: 'john@example.com' } }).json(); ``` -------------------------------- ### Vue: Install and Import useHookFetch Source: https://github.com/jsonlee12138/hook-fetch/blob/main/apps/docs/i18n/en/docusaurus-plugin-content-docs/current/framework-integration.md Shows how to install and import the `useHookFetch` composable from the 'hook-fetch/vue' package for use in Vue 3 applications. It also includes the import for the main `hookFetch` instance. ```typescript import { useHookFetch } from 'hook-fetch/vue'; import hookFetch from 'hook-fetch'; ``` -------------------------------- ### Set Up Global Error Handling with Hook-Fetch Plugin Source: https://github.com/jsonlee12138/hook-fetch/blob/main/apps/docs/i18n/en/docusaurus-plugin-content-docs/current/reference/faq.md Illustrates how to implement global error handling using a custom Hook-Fetch plugin. This example shows logging errors and redirecting to a login page for unauthorized (401) errors. ```typescript function errorHandlerPlugin() { return { name: 'error-handler', async onError(error, config) { console.error(`API Error [${config.method}] ${config.url}:`, error); if (error.response?.status === 401) { // Handle unauthorized window.location.href = '/login'; } return error; } }; } const api = hookFetch.create({ plugins: [errorHandlerPlugin()] }); ``` -------------------------------- ### Basic GET and POST Requests (JavaScript) Source: https://github.com/jsonlee12138/hook-fetch/blob/main/apps/docs/i18n/en/docusaurus-plugin-content-docs/current/api-reference.md Illustrates basic usage of Hook-Fetch for making simple GET and POST requests. The `json()` method is used to parse the response body as JSON. The POST example shows how to include data and set the method and content type. ```javascript // Simple GET request const data = await hookFetch('https://api.example.com/data').json(); // POST with data const result = await hookFetch('https://api.example.com/users', { method: 'POST', data: { name: 'John', email: 'john@example.com' } }).json(); ``` -------------------------------- ### Custom Hook-Fetch Plugin Example (TypeScript) Source: https://github.com/jsonlee12138/hook-fetch/blob/main/README.en.md Provides an example of creating and registering a custom plugin for hook-fetch to transform stream chunks, specifically for SSE text decoding. ```typescript // Custom plugin example: SSE text decoding plugin // This is just an example. It's recommended to use the provided `sseTextDecoderPlugin` which has more comprehensive handling function ssePlugin() { const decoder = new TextDecoder('utf-8'); return { name: 'sse', async transformStreamChunk(chunk, config) { if (!chunk.error) { chunk.result = decoder.decode(chunk.result, { stream: true }); } return chunk; } }; } // Register the plugin api.use(ssePlugin()); // Use the request with the plugin const req = api.get('/sse-endpoint'); for await (const chunk of req.stream()) { console.log(chunk.result); // Processed into text by the plugin } ``` -------------------------------- ### Hook-Fetch Error Handling with Try-Catch Blocks Source: https://github.com/jsonlee12138/hook-fetch/blob/main/apps/docs/i18n/en/docusaurus-plugin-content-docs/current/getting-started.md Demonstrates how to handle errors that may occur during network requests using a try-catch block. It checks for different error types: server response errors (status code, data), request errors (no response received), and other general errors. ```typescript try { const response = await api.get('/posts/999').json(); } catch (error) { if (error.response) { // Server responded with error status code console.log('Error status:', error.response.status); console.log('Error data:', error.response.data); } else if (error.request) { // Request was sent but no response received console.log('No response received'); } else { // Other errors console.log('Error:', error.message); } } ``` -------------------------------- ### Streaming Chat Component with hook-fetch and SSE Source: https://github.com/jsonlee12138/hook-fetch/blob/main/apps/docs/docs/framework-integration.md Implements a streaming chat component using hook-fetch's SSE (Server-Sent Events) plugin. This example shows how to configure hook-fetch for streaming responses, handle incoming message chunks, and display them in real-time. It also includes input handling and cancellation. ```vue ``` -------------------------------- ### Performant Plugin Example (TypeScript) Source: https://github.com/jsonlee12138/hook-fetch/blob/main/apps/docs/i18n/en/docusaurus-plugin-content-docs/current/plugins.md Demonstrates how to create a performant plugin by avoiding blocking operations. It uses `setImmediate` for background tasks, ensuring the main thread remains unblocked. This is crucial for maintaining application responsiveness. ```typescript function performantPlugin() { return { name: 'performant-plugin', async beforeRequest(config) { // Use non-blocking operations setImmediate(() => { // Background task updateMetrics(config); }); return config; } }; } ``` -------------------------------- ### Hook-Fetch Request Configuration: Timeouts and Custom Headers Source: https://github.com/jsonlee12138/hook-fetch/blob/main/apps/docs/i18n/en/docusaurus-plugin-content-docs/current/getting-started.md Explains how to configure request timeouts and custom headers in Hook-Fetch. Timeouts can be set globally when creating an instance or individually for specific requests. Custom headers can also be set globally or per request. ```typescript // Timeout Settings // Global timeout const api = hookFetch.create({ timeout: 5000 // 5 seconds }); // Individual request timeout const response = await api.get('/posts', {}, { timeout: 10000 // 10 seconds }).json(); // Custom Headers // Global headers const apiWithGlobalHeaders = hookFetch.create({ headers: { 'Authorization': 'Bearer your-token', 'Content-Type': 'application/json' } }); // Individual request headers const responseWithCustomHeaders = await api.get('/posts', {}, { headers: { 'Custom-Header': 'custom-value' } }).json(); ``` -------------------------------- ### Basic Hook-Fetch Usage (TypeScript) Source: https://github.com/jsonlee12138/hook-fetch/blob/main/README.en.md Demonstrates how to make a simple GET request and a POST request using the hook-fetch library. It shows how to access JSON data from the response. ```typescript import hookFetch from 'hook-fetch'; // Make a GET request const response = await hookFetch('https://example.com/api/data').json(); console.log(response); // Call json() method to parse response data as JSON // Using other HTTP methods const postResponse = await hookFetch('https://example.com/api/data', { method: 'POST', data: { name: 'hook-fetch' } }).json(); ``` -------------------------------- ### Hook-Fetch Plugin Lifecycle Example in TypeScript Source: https://github.com/jsonlee12138/hook-fetch/blob/main/packages/core/README.en.md Demonstrates the usage of each lifecycle hook in Hook-Fetch. These hooks allow for pre-request modification, post-response processing, stream transformation, error handling, and finalization. Each hook can be synchronous or asynchronous. ```typescript function examplePlugin() { return { name: 'example', priority: 1, // Priority, lower numbers have higher priority // Pre-request processing async beforeRequest(config) { // Can modify request configuration config.headers = new Headers(config.headers); config.headers.set('authorization', `Bearer ${tokenValue}`); return config; }, // Post-response processing async afterResponse(context) { // Can process response data. context.result is the result after being processed by methods like json() if (context.responseType === 'json') { // For example, determine if the request is truly successful based on the backend's business code if (context.result.code === 200) { // Business success, return context directly return context; } else { // Business failure, actively throw a ResponseError, which will be caught in the onError hook throw new ResponseError({ message: context.result.message, // Use the error message from the backend status: context.result.code, // Use the business code as the status response: context.response, // Original Response object config: context.config, name: 'BusinessError' // Custom error name }); } } return context; }, // Stream initialization processing, for advanced usage refer to sseTextDecoderPlugin (https://github.com/JsonLee12138/hook-fetch/blob/main/src/plugins/sse.ts) async beforeStream(body, config) { // Can transform or wrap the stream return body; }, // Stream chunk processing, supports returning iterators and async iterators which will be automatically processed into multiple messages async transformStreamChunk(chunk, config) { // Can process each data chunk if (!chunk.error) { chunk.result = `Processed: ${chunk.result}`; } return chunk; }, // Error handling async onError(error) { // The error object could be a network error or a ResponseError thrown from afterResponse // You can handle errors uniformly here, e.g., reporting, logging, or transforming the error info if (error.name === 'BusinessError') { // Handle custom business errors console.error(`Business Error: ${error.message}`); } else if (error.status === 401) { // Handle unauthorized error console.error('Login has expired, please log in again'); // window.location.href = '/login'; } // Re-throw the processed (or original) error so it can be caught by the final catch block return error; }, // Request completion processing async onFinally(context, config) { // Clean up resources or log console.log(`Request to ${config.url} completed`); } }; } ``` -------------------------------- ### Custom Plugin Implementation (JavaScript) Source: https://github.com/jsonlee12138/hook-fetch/blob/main/apps/docs/i18n/en/docusaurus-plugin-content-docs/current/api-reference.md Demonstrates how to create and use a custom plugin with Hook-Fetch. The `loggerPlugin` example shows a plugin that logs the request URL before the request is sent, using the `beforeRequest` hook. Plugins are added to an instance using the `use()` method. ```javascript const loggerPlugin = { name: 'logger', beforeRequest: (config) => { console.log(`Making request to: ${config.url}`); return config; } }; api.use(loggerPlugin); ``` -------------------------------- ### Create Basic Plugins for hook-fetch Source: https://context7.com/jsonlee12138/hook-fetch/llms.txt Explains how to create custom plugins for hook-fetch to intercept and modify requests or responses. The example shows an authentication plugin that adds an `Authorization` header and a logger plugin that logs request and response details. ```typescript import hookFetch from 'hook-fetch'; // Authentication plugin function authPlugin(token) { return { name: 'auth', priority: 1, async beforeRequest(config) { config.headers = new Headers(config.headers); config.headers.set('Authorization', `Bearer ${token}`); return config; } }; } // Logging plugin function loggerPlugin() { return { name: 'logger', async beforeRequest(config) { console.log(`[REQUEST] ${config.method} ${config.url}`); return config; }, async afterResponse(context) { console.log(`[RESPONSE] ${context.response.status}`); return context; } }; } // Create instance with plugins const api = hookFetch.create({ baseURL: 'https://api.example.com', plugins: [authPlugin('my-token-123'), loggerPlugin()] }); const result = await api.get('/users/1').json(); // Console output: // [REQUEST] GET /users/1 // [RESPONSE] 200 // result: { id: 1, name: 'John' } ``` -------------------------------- ### RENAMED Requirement Example Source: https://github.com/jsonlee12138/hook-fetch/blob/main/openspec/AGENTS.md This markdown snippet illustrates the correct format for documenting a renamed requirement, specifying the 'FROM' and 'TO' states. ```markdown ## RENAMED Requirements - FROM: `### Requirement: Login` - TO: `### Requirement: User Authentication` ``` -------------------------------- ### HookFetch Plugin Priority Example Source: https://github.com/jsonlee12138/hook-fetch/blob/main/apps/docs/i18n/en/docusaurus-plugin-content-docs/current/plugins.md Illustrates how to set priorities for plugins to control their execution order. Lower priority numbers indicate higher priority, meaning they execute earlier in the lifecycle. ```typescript const highPriorityPlugin = { name: 'high-priority', priority: 1, beforeRequest(config) { // Executes first return config; } }; const lowPriorityPlugin = { name: 'low-priority', priority: 10, beforeRequest(config) { // Executes later return config; } }; ``` -------------------------------- ### Implement Service Layer for API Interactions (TypeScript) Source: https://github.com/jsonlee12138/hook-fetch/blob/main/apps/docs/i18n/en/docusaurus-plugin-content-docs/current/best-practices.md Showcases the service layer pattern to abstract API calls, providing a cleaner interface for business logic. This example defines a `UserService` class with methods to fetch, create, and update users, encapsulating the `userApi` calls and handling potential errors. ```typescript // services/UserService.ts import { userApi } from '../api/users'; export class UserService { static async getUser(id: string): Promise { try { const response = await userApi.getUser(id).json(); return response.data; } catch (error) { throw new Error(`Failed to fetch user: ${error.message}`); } } static async createUser(userData: Omit): Promise { try { const response = await userApi.createUser(userData).json(); return response.data; } catch (error) { throw new Error(`Failed to create user: ${error.message}`); } } } ``` -------------------------------- ### HTTP Method Shortcuts Source: https://context7.com/jsonlee12138/hook-fetch/llms.txt Utilize convenient shorthand methods (get, post, put, patch, delete, head, options) provided by Hook-Fetch instances for common HTTP operations. ```APIDOC ## HTTP Method Shortcuts ### Description Convenient shorthand methods for common HTTP operations like GET, POST, PUT, PATCH, DELETE, HEAD, and OPTIONS are available on Hook-Fetch instances. ### Method - `get(url, params?)` - `post(url, data?)` - `put(url, data?)` - `patch(url, data?)` - `delete(url)` - `head(url)` - `options(url)` ### Endpoint Relative to the `baseURL` configured for the instance. ### Parameters #### Path Parameters None directly on the shortcut methods, but included in the `url`. #### Query Parameters - **params** (object) - For `get` requests, an optional object of query parameters. #### Request Body - **data** (object) - For `post`, `put`, `patch` requests, the data to send in the request body. ### Request Example ```javascript const api = hookFetch.create({ baseURL: 'https://api.example.com' }); // GET request with query parameters const users = await api.get('/users', { page: 1, limit: 10 }).json(); // URL: https://api.example.com/users?page=1&limit=10 // POST request const newUser = await api.post('/users', { name: 'John', age: 30 }).json(); // PUT request - full update const updatedUser = await api.put('/users/1', { name: 'John Doe', age: 31, email: 'john@example.com' }).json(); // PATCH request - partial update const patchedUser = await api.patch('/users/1', { age: 32 }).json(); // DELETE request const deleteResult = await api.delete('/users/1').json(); // HEAD request - get headers only const headers = await api.head('/users/1'); console.log(headers.status); // OPTIONS request const options = await api.options('/users'); ``` ### Response #### Success Response (200) - **response** (object) - The parsed response body or headers depending on the method and handler used. #### Response Example ```json { "id": 1, "name": "John Doe", "age": 32, "email": "john@example.com" } ``` ``` -------------------------------- ### Handle Errors in Hook-Fetch Requests Source: https://github.com/jsonlee12138/hook-fetch/blob/main/apps/docs/i18n/en/docusaurus-plugin-content-docs/current/reference/faq.md Provides an example of how to use a try-catch block to handle potential errors during Hook-Fetch requests, differentiating between server errors, network errors, and other exceptions. ```typescript try { const response = await api.get('/users/1').json(); } catch (error) { if (error.response) { // Server responded with error status console.log('Status:', error.response.status); console.log('Data:', error.response.data); } else if (error.request) { // Request was sent but no response received console.log('Network error'); } else { // Other error console.log('Error:', error.message); } } ``` -------------------------------- ### Convenience HTTP Methods Source: https://github.com/jsonlee12138/hook-fetch/blob/main/apps/docs/i18n/en/docusaurus-plugin-content-docs/current/api-reference.md Provides shortcut methods for common HTTP request types like GET, POST, PUT, DELETE, etc., simplifying the process of making specific API calls. ```APIDOC ## Convenience Methods ### `get(url, params?, options?)` Makes a GET request. **Parameters:** - `url` (string): Request URL - `params` (object, optional): Query parameters - `options` (GetOptions, optional): Request configuration **Example:** ```typescript const users = await get('/users', { page: 1, limit: 10 }).json(); ``` ### `post(url, data?, options?)` Makes a POST request. **Parameters:** - `url` (string): Request URL - `data` (any, optional): Request body data - `options` (PostOptions, optional): Request configuration **Example:** ```typescript const newUser = await post('/users', { name: 'John', email: 'john@example.com' }).json(); ``` ### `put(url, data?, options?)` Makes a PUT request. ### `patch(url, data?, options?)` Makes a PATCH request. ### `del(url, options?)` Makes a DELETE request. ### `head(url, params?, options?)` Makes a HEAD request. ### `options(url, params?, options?)` Makes an OPTIONS request. ### `upload(url, data?, options?)` Makes a file upload request. **Example:** ```typescript const result = await upload('/upload', { file: fileInput.files[0], name: 'My File' }).json(); ``` ``` -------------------------------- ### Plugin Lifecycle Hooks Source: https://github.com/jsonlee12138/hook-fetch/blob/main/README.en.md This section provides examples of how to implement and use the various plugin lifecycle hooks available in Hook-Fetch. These hooks allow you to intercept and modify requests and responses at different stages of their execution. ```APIDOC ## Plugin Lifecycle Hooks All lifecycle hooks support both synchronous and asynchronous operations. They can return either a Promise or a direct value. Each hook function receives the current configuration object (`config`), which can be used to make decisions and handle different request scenarios. ### `beforeRequest(config)` - **Description**: Pre-request processing. Can modify request configuration. - **Method**: Asynchronous - **Example**: Modifies headers to include an authorization token. ### `afterResponse(context)` - **Description**: Post-response processing. Can process response data. - **Method**: Asynchronous - **Example**: Checks the business code in JSON responses and throws a `ResponseError` for business failures. ### `beforeStream(body, config)` - **Description**: Stream initialization processing. Can transform or wrap the stream. - **Method**: Asynchronous - **Example**: Returns the stream body directly. ### `transformStreamChunk(chunk, config)` - **Description**: Stream chunk processing. Supports returning iterators and async iterators. - **Method**: Asynchronous - **Example**: Processes each data chunk, adding a "Processed: " prefix if no error exists. ### `onError(error)` - **Description**: Error handling. Catches network errors or `ResponseError` from `afterResponse`. - **Method**: Asynchronous - **Example**: Logs business errors or unauthorized errors and can optionally redirect the user. ### `onFinally(context, config)` - **Description**: Request completion processing. Used for cleanup or logging. - **Method**: Asynchronous - **Example**: Logs the completion of a request to a specific URL. ``` -------------------------------- ### hook-fetch Deduplication Behavior Examples Source: https://github.com/jsonlee12138/hook-fetch/blob/main/apps/docs/i18n/en/docusaurus-plugin-content-docs/current/plugins.md Illustrates the behavior of the `dedupePlugin` in `hook-fetch` under various conditions, including concurrent identical requests, sequential requests, requests with different parameters, and requests with different HTTP methods. ```typescript const api = hookFetch.create({ plugins: [dedupePlugin({})] }); // ✅ Concurrent identical requests will be deduplicated Promise.all([ api.get('/users/1').json(), // Executes normally api.get('/users/1').json(), // Deduplicated, throws error ]); // ✅ Sequential requests will not be deduplicated await api.get('/users/1').json(); // First request await api.get('/users/1').json(); // Second request, executes normally // ✅ Requests with different parameters will not be deduplicated Promise.all([ api.get('/users/1', { params: { page: 1 } }).json(), // Executes normally api.get('/users/1', { params: { page: 2 } }).json(), // Executes normally ]); // ✅ Requests with different HTTP methods will not be deduplicated Promise.all([ api.get('/users/1').json(), // Executes normally api.post('/users/1').json(), // Executes normally ]); ``` -------------------------------- ### ChatGPT-style Streaming Chat Implementation Source: https://github.com/jsonlee12138/hook-fetch/blob/main/apps/docs/i18n/en/docusaurus-plugin-content-docs/current/streaming.md Provides an example of a real-time chat interface that mimics ChatGPT's streaming behavior using Hook-Fetch and the SSE plugin. It sends a user message and progressively displays the AI's response as it arrives. ```typescript import { sseTextDecoderPlugin } from 'hook-fetch/plugins/sse'; const chatApi = hookFetch.create({ baseURL: 'https://api.openai.com/v1', headers: { 'Authorization': 'Bearer your-api-key', 'Content-Type': 'application/json' }, plugins: [ sseTextDecoderPlugin({ json: true, prefix: 'data: ', doneSymbol: '[DONE]' }) ] }); async function streamChat(message: string) { const request = chatApi.post('/chat/completions', { model: 'gpt-3.5-turbo', messages: [{ role: 'user', content: message }], stream: true }); let fullResponse = ''; for await (const chunk of request.stream()) { const delta = chunk.result?.choices?.[0]?.delta?.content; if (delta) { fullResponse += delta; console.log('Streaming:', delta); // Update UI display updateChatUI(fullResponse); } } return fullResponse; } ``` -------------------------------- ### Hook-Fetch Plugin Lifecycle Example (TypeScript) Source: https://github.com/jsonlee12138/hook-fetch/blob/main/README.en.md Demonstrates the usage of various lifecycle hooks within a Hook-Fetch plugin. These hooks allow for pre-request modification, post-response processing, stream handling, and error management. All hooks support synchronous and asynchronous operations. ```typescript function examplePlugin() { return { name: 'example', priority: 1, async beforeRequest(config) { config.headers = new Headers(config.headers); config.headers.set('authorization', `Bearer ${tokenValue}`); return config; }, async afterResponse(context) { if (context.responseType === 'json') { if (context.result.code === 200) { return context; } else { throw new ResponseError({ message: context.result.message, status: context.result.code, response: context.response, config: context.config, name: 'BusinessError' }); } } return context; }, async beforeStream(body, config) { return body; }, async transformStreamChunk(chunk, config) { if (!chunk.error) { chunk.result = `Processed: ${chunk.result}`; } return chunk; }, async onError(error) { if (error.name === 'BusinessError') { console.error(`Business Error: ${error.message}`); } else if (error.status === 401) { console.error('Login has expired, please log in again'); } return error; }, async onFinally(context, config) { console.log(`Request to ${config.url} completed`); } }; } ``` -------------------------------- ### Creating Configured Instances with Hook-Fetch (TypeScript) Source: https://context7.com/jsonlee12138/hook-fetch/llms.txt Shows how to create a reusable Hook-Fetch instance with shared configuration like baseURL, headers, and timeout. This simplifies making multiple requests to the same API endpoint. Supports common HTTP methods like GET and POST. ```typescript import hookFetch from 'hook-fetch'; // Create instance with base configuration const api = hookFetch.create({ baseURL: 'https://api.example.com', headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer token123' }, timeout: 5000, withCredentials: true }); // Use instance for requests const userData = await api.get('/users/1').json(); console.log(userData); // Output: { id: 1, name: 'John', email: 'john@example.com' } const newUser = await api.post('/users', { name: 'Jane', email: 'jane@example.com' }).json(); console.log(newUser); // Output: { id: 2, name: 'Jane', email: 'jane@example.com', createdAt: '2025-01-13' } ``` -------------------------------- ### VS Code Hint Plugin Reference Path (TypeScript) Source: https://github.com/jsonlee12138/hook-fetch/blob/main/README.en.md Provides the necessary VS Code triple-slash directives to reference Hook-Fetch's plugin, React, and Vue type definitions. This setup helps with IntelliSense and type checking in your project. ```typescript // Create a file hook-fetch.d.ts in src with the following content /// /// /// ``` -------------------------------- ### VS Code Hint Plugin Reference Path (TypeScript) Source: https://github.com/jsonlee12138/hook-fetch/blob/main/packages/core/README.en.md Provides VS Code directive references for enabling intelligent code completion and type checking for Hook-Fetch plugins, React hooks, and Vue hooks. This setup helps developers by providing real-time feedback and suggestions within their editor. ```typescript // Create a file hook-fetch.d.ts in src with the following content /// /// /// ``` -------------------------------- ### Custom Stream Processing Plugin Source: https://github.com/jsonlee12138/hook-fetch/blob/main/apps/docs/i18n/en/docusaurus-plugin-content-docs/current/streaming.md Demonstrates creating a custom plugin for Hook-Fetch to modify stream chunks during processing. The `customStreamPlugin` example shows how to intercept each chunk, apply custom logic (e.g., `processChunk`), and return the modified chunk. ```typescript const customStreamPlugin = () => ({ name: 'custom-stream', async transformStreamChunk(chunk, config) { if (!chunk.error && chunk.result) { // Custom processing logic const processedData = processChunk(chunk.result); chunk.result = processedData; } return chunk; } }); const api = hookFetch.create({ plugins: [customStreamPlugin()] }); ``` -------------------------------- ### HTTP Method Shortcuts with Hook-Fetch (TypeScript) Source: https://context7.com/jsonlee12138/hook-fetch/llms.txt Illustrates the convenient shorthand methods provided by Hook-Fetch for common HTTP operations like GET, POST, PUT, PATCH, DELETE, HEAD, and OPTIONS. These methods simplify API interactions by abstracting the HTTP method and common configurations. ```typescript const api = hookFetch.create({ baseURL: 'https://api.example.com' }); // GET request with query parameters const users = await api.get('/users', { page: 1, limit: 10 }).json(); // URL: https://api.example.com/users?page=1&limit=10 // POST request const newUser = await api.post('/users', { name: 'John', age: 30 }).json(); // PUT request - full update const updatedUser = await api.put('/users/1', { name: 'John Doe', age: 31, email: 'john@example.com' }).json(); // PATCH request - partial update const patchedUser = await api.patch('/users/1', { age: 32 }).json(); // DELETE request const deleteResult = await api.delete('/users/1').json(); // HEAD request - get headers only const headers = await api.head('/users/1'); console.log(headers.status); // Output: 200 // OPTIONS request const options = await api.options('/users'); console.log(options); ``` -------------------------------- ### Implement Full Plugin Lifecycle Hooks Source: https://context7.com/jsonlee12138/hook-fetch/llms.txt Demonstrates the complete plugin lifecycle in hook-fetch, covering request modification, response processing, stream handling, error management, and cleanup. It utilizes `ResponseError` for custom error handling and provides a complete `hookFetch` instance setup. ```typescript import { ResponseError } from 'hook-fetch'; function fullLifecyclePlugin() { return { name: 'full-lifecycle', priority: 1, async beforeRequest(config) { // Modify request before sending console.log('Preparing request:', config.url); config.headers = new Headers(config.headers); config.headers.set('X-Request-Time', Date.now().toString()); return config; }, async afterResponse(context) { // Process response after receiving console.log('Response received:', context.response.status); if (context.responseType === 'json') { // Check business logic response if (context.result.code === 200) { return context; } else { // Throw custom error for business failures throw new ResponseError({ message: context.result.message, status: context.result.code, response: context.response, config: context.config, name: 'BusinessError' }); } } return context; }, async beforeStream(body, config) { // Transform or wrap stream before processing console.log('Stream starting for:', config.url); return body; }, async transformStreamChunk(chunk, config) { // Process each stream chunk if (!chunk.error) { chunk.result = `[Processed] ${chunk.result}`; } return chunk; }, async onError(error) { // Unified error handling console.error('Request error:', error.name); if (error.name === 'BusinessError') { console.error('Business error:', error.message); } else if (error.status === 401) { console.error('Unauthorized - redirecting to login'); } return error; }, async onFinally(context, config) { // Cleanup or logging after request completes console.log(`Request to ${config.url} completed`); } }; } const api = hookFetch.create({ baseURL: 'https://api.example.com', plugins: [fullLifecyclePlugin()] }); try { const result = await api.get('/users').json(); console.log(result); } catch (error) { console.error('Failed:', error.message); } ``` -------------------------------- ### Create Configured Hook-Fetch Instance Source: https://github.com/jsonlee12138/hook-fetch/blob/main/apps/docs/i18n/en/docusaurus-plugin-content-docs/current/reference/faq.md Shows how to create a reusable instance of Hook-Fetch with custom configurations like baseURL, headers, and timeout. ```typescript const api = hookFetch.create({ baseURL: 'https://api.example.com', headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer your-token' }, timeout: 5000 }); const users = await api.get('/users').json(); ``` -------------------------------- ### Creating a Configured Hook-Fetch Instance Source: https://github.com/jsonlee12138/hook-fetch/blob/main/apps/docs/i18n/en/docusaurus-plugin-content-docs/current/intro.md Illustrates how to create a custom instance of Hook-Fetch with pre-configured options such as baseURL, headers, and timeout. This instance can then be used for making requests with consistent settings. ```typescript // Create a configured instance const api = hookFetch.create({ baseURL: 'https://api.example.com', headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer your-token' }, timeout: 5000 }); // Use the instance const users = await api.get('/users').json(); ``` -------------------------------- ### Hook-Fetch Response Handling: Parsing JSON, Text, Blob, and More Source: https://github.com/jsonlee12138/hook-fetch/blob/main/apps/docs/i18n/en/docusaurus-plugin-content-docs/current/getting-started.md Shows various methods provided by Hook-Fetch to handle responses. You can parse the response body as JSON, plain text, Blob for file downloads, ArrayBuffer for binary data, FormData, or raw bytes. These methods are chained after making a request. ```typescript const request = api.get('/posts/1'); // JSON parsing const jsonData = await request.json(); // Text parsing const textData = await request.text(); // Blob handling (for file downloads) const blobData = await request.blob(); // ArrayBuffer handling const arrayBufferData = await request.arrayBuffer(); // FormData handling const formData = await request.formData(); // Byte data const bytesData = await request.bytes(); ``` -------------------------------- ### Scaffolding a New Change with openspec CLI Source: https://github.com/jsonlee12138/hook-fetch/blob/main/openspec/AGENTS.md This snippet demonstrates how to initiate a new change using the 'openspec' command-line tool. It includes creating directories for proposal, tasks, and specifications, and then populating these files with initial content. ```bash # 1) Explore current state openspec spec list --long openspec list # Optional full-text search: # rg -n "Requirement: |Scenario:" openspec/specs # rg -n "^#|Requirement:" openspec/changes # 2) Choose change id and scaffold CHANGE=add-two-factor-auth mkdir -p openspec/changes/$CHANGE/{specs/auth} printf "## Why\n...\n\n## What Changes\n- ...\n\n## Impact\n- ...\n" > openspec/changes/$CHANGE/proposal.md printf "## 1. Implementation\n- [ ] 1.1 ...\n" > openspec/changes/$CHANGE/tasks.md # 3) Add deltas (example) cat > openspec/changes/$CHANGE/specs/auth/spec.md << 'EOF' ## ADDED Requirements ### Requirement: Two-Factor Authentication Users MUST provide a second factor during login. #### Scenario: OTP required - **WHEN** valid credentials are provided - **THEN** an OTP challenge is required EOF # 4) Validate openspec validate $CHANGE --strict ``` -------------------------------- ### Convenience GET Method (TypeScript) Source: https://github.com/jsonlee12138/hook-fetch/blob/main/apps/docs/i18n/en/docusaurus-plugin-content-docs/current/api-reference.md A shortcut function for making GET requests. It accepts a URL, optional query parameters, and request configuration. ```typescript const users = await get('/users', { page: 1, limit: 10 }).json(); ``` -------------------------------- ### Registering HookFetch Plugins Source: https://github.com/jsonlee12138/hook-fetch/blob/main/apps/docs/i18n/en/docusaurus-plugin-content-docs/current/plugins.md Demonstrates two methods for registering plugins with Hook-Fetch: during instance creation using the `create` method and after instance creation using the `use` method. ```typescript // Register during instance creation const api = hookFetch.create({ baseURL: 'https://api.example.com', plugins: [myPlugin(), anotherPlugin()] }); // Or use the use method api.use(myPlugin()); ``` -------------------------------- ### Generic API with TypeScript Support Source: https://github.com/jsonlee12138/hook-fetch/blob/main/README.en.md Demonstrates how to create a generic API instance with Hook-Fetch, enabling strong typing for requests and responses. ```APIDOC ## Generic API with TypeScript Support Hook-Fetch provides comprehensive TypeScript support, allowing you to define explicit types for requests and responses. ### `hookFetch.create(options)` - **Description**: Creates a typed instance of Hook-Fetch. - **Parameters**: - `T` (Type): The expected response data type. - `K` (string, optional): The key within the response object that holds the actual data (e.g., 'data'). - **Options**: Configuration object for the API instance (see `RequestOptions`). ### Request Example: ```typescript interface BaseResponseVO { code: number; data: any; message: string; } const request = hookFetch.create({ baseURL: 'https://example.com', headers: { 'Content-Type': 'application/json', }, timeout: 5000, }); interface User { id: number; name: string; email: string; } // Use the type in a request const res = await request.get('/users/1').json(); console.log(res.data); // TypeScript provides complete type hints ``` ```