### Start Static File Server with npx serve Source: https://github.com/arktomson/ajaxinterceptor/blob/master/examples/README.md Start a static file server from the repository root using npx serve. This is useful for serving the example files locally. ```bash npx serve . ``` -------------------------------- ### Install ajax-hooker Source: https://github.com/arktomson/ajaxinterceptor/blob/master/README.zh-CN.md Install the ajax-hooker library using npm. ```bash npm install ajax-hooker ``` -------------------------------- ### Quick Start: Initialize and Hook Requests Source: https://github.com/arktomson/ajaxinterceptor/blob/master/README.zh-CN.md Get the interceptor instance, inject it to start interception, and add a hook function to modify requests and capture responses. ```typescript import AjaxInterceptor from 'ajax-hooker'; // 获取拦截器实例 const interceptor = AjaxInterceptor.getInstance(); // 注入拦截器 interceptor.inject(); // 添加钩子函数 interceptor.hook((request) => { // 修改请求 request.headers.set('Authorization', 'Bearer token'); // 捕获响应 request.response = async (response) => { console.log('响应状态:', response.status); console.log('响应数据:', response.json); }; return request; }); ``` -------------------------------- ### Quick Start: Initialize and Hook Requests Source: https://github.com/arktomson/ajaxinterceptor/blob/master/README.md Get the interceptor instance, inject it into the browser, and add a hook to modify requests and capture responses. ```typescript import AjaxInterceptor from 'ajax-hooker'; // Get the interceptor instance const interceptor = AjaxInterceptor.getInstance(); // Inject the interceptor interceptor.inject(); // Add a hook interceptor.hook((request) => { // Modify the request request.headers.set('Authorization', 'Bearer token'); // Capture the response request.response = async (response) => { console.log('Status:', response.status); console.log('Data:', response.json); }; return request; }); ``` -------------------------------- ### Run Development Server with pnpm Source: https://github.com/arktomson/ajaxinterceptor/blob/master/README.md Starts the development server in watch mode for continuous building. ```bash pnpm dev ``` -------------------------------- ### Install Dependencies with pnpm Source: https://github.com/arktomson/ajaxinterceptor/blob/master/README.md Installs project dependencies using the pnpm package manager. ```bash pnpm install ``` -------------------------------- ### Initialize and Inject AjaxHooker Source: https://github.com/arktomson/ajaxinterceptor/blob/master/examples/vanilla-xhr-fetch/index.html Get an instance of the AjaxHooker and inject it into the window to start intercepting requests. This setup is required before defining any hooks. ```javascript const interceptor = window.AjaxHooker.getInstance(); const logEl = document.getElementById("log"); function log(...args) { logEl.textContent += `${args.join(" ")}\n`; } interceptor.inject(); ``` -------------------------------- ### Add Auth Token Example Source: https://github.com/arktomson/ajaxinterceptor/blob/master/README.md Shows how to add an Authorization token to request headers. ```APIDOC ### Add Auth Token ```typescript interceptor.hook((request) => { request.headers.set('Authorization', `Bearer ${getToken()}`); return request; }); ``` ``` -------------------------------- ### Build Library with pnpm Source: https://github.com/arktomson/ajaxinterceptor/blob/master/examples/README.md Build the library using pnpm. This command is typically run before starting local development or deploying. ```bash pnpm run build ``` -------------------------------- ### Capture Response Data Example Source: https://github.com/arktomson/ajaxinterceptor/blob/master/README.md Illustrates how to capture and log response data within the response callback. ```APIDOC ### Capture Response Data ```typescript interceptor.hook((request) => { request.response = async (response) => { console.log('Status:', response.status); // XHR uses response.response, Fetch uses response.json console.log('Data:', response.json || response.response); }; return request; }); ``` ``` -------------------------------- ### Modify XHR Properties Example Source: https://github.com/arktomson/ajaxinterceptor/blob/master/README.md Demonstrates how to modify specific properties for XHR requests. ```APIDOC ### Modify XHR Properties ```typescript interceptor.hook((request) => { // Change response type request.responseType = 'json'; // Set timeout request.timeout = 5000; // Send credentials request.withCredentials = true; return request; }, 'xhr'); ``` ``` -------------------------------- ### Request Modification and Response Handling Source: https://github.com/arktomson/ajaxinterceptor/blob/master/README.zh-CN.md Examples demonstrating how to modify requests before they are sent and handle responses after they are received. ```APIDOC ## Request Modification and Response Handling (v1.1+) ### Unified Request Pre/Post Lifecycle This example shows how to modify request parameters before sending and handle responses using a unified callback model for both XHR and Fetch. ### Method `interceptor.hook(request => { ... request.response = async (response) => { ... }; return request; })` ### Request Example ```typescript interceptor.hook((request) => { // Before request: Modify request parameters request.url = request.url.replace('/api/v1', '/api/v2'); request.headers.set('x-trace-id', crypto.randomUUID()); // After request: Unified response callback for XHR + Fetch request.response = async (response) => { console.log('status:', response.status); }; return request; }); ``` ``` -------------------------------- ### Simulate Fetch Network Errors Example Source: https://github.com/arktomson/ajaxinterceptor/blob/master/README.md Shows how to simulate network errors for Fetch requests using `mockError`. ```APIDOC ### Simulate Fetch Network Errors ```typescript interceptor.hook((request) => { if (request.url.includes('/api/fail')) { request.response = (response) => { response.mockError = new TypeError('Failed to fetch'); }; } return request; }, 'fetch'); ``` **Note:** `mockError` is designed for **Fetch only**. For XHR failure simulation, prefer setting `request.timeout` and using a slow or hanging endpoint to trigger native timeout behavior. ``` -------------------------------- ### Log Requests and Responses Source: https://context7.com/arktomson/ajaxinterceptor/llms.txt Create comprehensive logs for requests and responses. This example logs request details and response status/duration. Ensure `crypto.randomUUID` is available in your environment. ```typescript import AjaxInterceptor from 'ajax-hooker'; const interceptor = AjaxInterceptor.getInstance(); interceptor.inject(); const requestLogs = []; interceptor.hook((request) => { const startTime = Date.now(); const requestId = crypto.randomUUID(); // Log request requestLogs.push({ id: requestId, type: request.type, method: request.method, url: request.url, timestamp: new Date().toISOString(), }); // Log response request.response = async (response) => { const duration = Date.now() - startTime; requestLogs.push({ id: requestId, status: response.status, statusText: response.statusText, duration: `${duration}ms`, timestamp: new Date().toISOString(), }); console.log(`[${request.type}] ${request.method} ${request.url} -> ${response.status} (${duration}ms)`); }; return request; }); ``` -------------------------------- ### API Change Example: Unified Request Lifecycle Source: https://github.com/arktomson/ajaxinterceptor/blob/master/README.zh-CN.md Demonstrates modifying request parameters before the request and handling responses uniformly after the request for both XHR and Fetch. ```typescript interceptor.hook((request) => { // 请求前: 改写请求参数 request.url = request.url.replace('/api/v1', '/api/v2'); request.headers.set('x-trace-id', crypto.randomUUID()); // 请求后: XHR + Fetch 统一响应回调 request.response = async (response) => { console.log('status:', response.status); }; return request; }); ``` -------------------------------- ### Rewrite Request URL Example Source: https://github.com/arktomson/ajaxinterceptor/blob/master/README.md Demonstrates how to modify the request URL using the interceptor's hook. ```APIDOC ### Rewrite Request URL ```typescript interceptor.hook((request) => { if (request.url.includes('/api/v1/')) { request.url = request.url.replace('/api/v1/', '/api/v2/'); } return request; }); ``` ``` -------------------------------- ### Inject Interceptor Source: https://github.com/arktomson/ajaxinterceptor/blob/master/README.zh-CN.md Inject the interceptor to start intercepting requests. Can specify 'xhr' or 'fetch', or both by default. ```typescript // 注入所有 interceptor.inject(); // 只注入 XHR interceptor.inject('xhr'); // 只注入 Fetch interceptor.inject('fetch'); ``` -------------------------------- ### Inject AjaxInterceptor Source: https://github.com/arktomson/ajaxinterceptor/blob/master/README.md Inject the interceptor to start intercepting requests. You can choose to inject for 'xhr', 'fetch', or both. ```typescript // Inject all interceptor.inject(); ``` ```typescript // Only XHR interceptor.inject('xhr'); ``` ```typescript // Only Fetch interceptor.inject('fetch'); ``` -------------------------------- ### Fine-Grained Control: Inject and Hook Fetch Only Source: https://github.com/arktomson/ajaxinterceptor/blob/master/README.md Control interception by specifying the request type. This example injects and hooks only Fetch requests. ```typescript // Inject only Fetch interception interceptor.inject('fetch'); // Hook only Fetch requests interceptor.hook((request) => { request.headers.set('x-from', 'fetch-only'); return request; }, 'fetch'); // Remove only Fetch interception interceptor.uninject('fetch'); ``` -------------------------------- ### Get Interceptor Instance Source: https://github.com/arktomson/ajaxinterceptor/blob/master/README.zh-CN.md Retrieve the singleton instance of the AjaxInterceptor. ```typescript const interceptor = AjaxInterceptor.getInstance(); ``` -------------------------------- ### Simulate Fetch Errors Source: https://context7.com/arktomson/ajaxinterceptor/llms.txt Test error handling by simulating network errors for specific endpoints or randomly. This example targets the 'fetch' API. Ensure your `try...catch` blocks are set up to handle these simulated errors. ```typescript import AjaxInterceptor from 'ajax-hooker'; const interceptor = AjaxInterceptor.getInstance(); interceptor.inject('fetch'); // Simulate network failure for specific endpoints interceptor.hook((request) => { if (request.url.includes('/api/unstable')) { request.response = (response) => { response.mockError = new TypeError('Failed to fetch'); }; } return request; }, 'fetch'); // Simulate random failures for testing interceptor.hook((request) => { if (Math.random() < 0.1) { // 10% failure rate request.response = (response) => { response.mockError = 'Network error'; }; } return request; }, 'fetch'); // Usage - these will reject with the mocked error try { await fetch('/api/unstable'); } catch (error) { console.error('Caught:', error.message); // "Failed to fetch" } ``` -------------------------------- ### Configure XHR Properties Source: https://context7.com/arktomson/ajaxinterceptor/llms.txt Modify XHR-specific properties like response type, timeout, and credentials. This example targets the 'xhr' API. Ensure the server response is compatible with the specified `responseType`. ```typescript import AjaxInterceptor from 'ajax-hooker'; const interceptor = AjaxInterceptor.getInstance(); interceptor.inject('xhr'); interceptor.hook((request) => { // Set response type for automatic parsing request.responseType = 'json'; // Set timeout (in milliseconds) request.timeout = 30000; // Include credentials (cookies) in cross-origin requests request.withCredentials = true; return request; }, 'xhr'); // XHR requests now have these properties configured const xhr = new XMLHttpRequest(); xhr.open('GET', '/api/data'); xhr.onload = () => { console.log('Response:', xhr.response); // Already parsed as JSON }; xhr.send(); ``` -------------------------------- ### URL Rewriting to Add Query Parameters Source: https://context7.com/arktomson/ajaxinterceptor/llms.txt Append dynamic query parameters to request URLs. This example adds a timestamp and platform parameter to every request. ```typescript import AjaxInterceptor from 'ajax-hooker'; const interceptor = AjaxInterceptor.getInstance(); interceptor.inject(); // Add query parameters interceptor.hook((request) => { const url = new URL(request.url); url.searchParams.set('timestamp', Date.now().toString()); url.searchParams.set('platform', 'web'); request.url = url.toString(); return request; }); ``` -------------------------------- ### URL Rewriting for API Version Switching Source: https://context7.com/arktomson/ajaxinterceptor/llms.txt Dynamically rewrite request URLs to switch between API versions. This example demonstrates replacing a specific version segment in the URL. ```typescript import AjaxInterceptor from 'ajax-hooker'; const interceptor = AjaxInterceptor.getInstance(); interceptor.inject(); // API version switching interceptor.hook((request) => { if (request.url.includes('/api/v1/')) { request.url = request.url.replace('/api/v1/', '/api/v2/'); } return request; }); ``` -------------------------------- ### inject(type?) Source: https://github.com/arktomson/ajaxinterceptor/blob/master/README.md Injects the interceptor to start intercepting requests. Can specify 'xhr' or 'fetch' to inject only one type. ```APIDOC ## inject(type?) ### Description Inject the interceptor and start intercepting requests. ### Method Instance method ### Endpoint N/A ### Parameters #### Query Parameters - **type** (string) - Optional - Specify 'xhr' or 'fetch' to inject only one type. If omitted, both are injected. ### Request Example ```typescript // Inject all interceptor.inject(); // Only XHR interceptor.inject('xhr'); // Only Fetch interceptor.inject('fetch'); ``` ### Response None ``` -------------------------------- ### inject(type?) Source: https://context7.com/arktomson/ajaxinterceptor/llms.txt Injects the AjaxInterceptor to start intercepting AJAX requests. You can specify whether to intercept 'xhr', 'fetch', or both. ```APIDOC ## inject(type?) ### Description Inject the interceptor to start intercepting AJAX requests. Can target specific request types ('xhr' or 'fetch') or both when no argument is provided. ### Method `interceptor.inject(type?: 'xhr' | 'fetch')` ### Parameters #### Query Parameters - **type** (string) - Optional - Specifies the type of requests to intercept. Can be 'xhr' or 'fetch'. If omitted, both are intercepted. ### Example ```typescript import AjaxInterceptor from 'ajax-hooker'; const interceptor = AjaxInterceptor.getInstance(); // Inject interception for both XHR and Fetch interceptor.inject(); // Or inject only for specific types interceptor.inject('xhr'); // Only intercept XMLHttpRequest interceptor.inject('fetch'); // Only intercept Fetch API ``` ``` -------------------------------- ### Get Singleton Interceptor Instance Source: https://context7.com/arktomson/ajaxinterceptor/llms.txt Retrieve the singleton instance of the AjaxInterceptor. Subsequent calls return the same instance. ```typescript import AjaxInterceptor from 'ajax-hooker'; // Get the singleton instance const interceptor = AjaxInterceptor.getInstance(); // The same instance is returned on subsequent calls const sameInstance = AjaxInterceptor.getInstance(); console.log(interceptor === sameInstance); // true ``` -------------------------------- ### Inject Interceptor for AJAX Requests Source: https://context7.com/arktomson/ajaxinterceptor/llms.txt Start intercepting AJAX requests. By default, it intercepts both XHR and Fetch. You can specify 'xhr' or 'fetch' to target specific types. ```typescript import AjaxInterceptor from 'ajax-hooker'; const interceptor = AjaxInterceptor.getInstance(); // Inject interception for both XHR and Fetch interceptor.inject(); // Or inject only for specific types interceptor.inject('xhr'); // Only intercept XMLHttpRequest interceptor.inject('fetch'); // Only intercept Fetch API ``` -------------------------------- ### Intercept Streaming Responses with AjaxInterceptor Source: https://github.com/arktomson/ajaxinterceptor/blob/master/README.md Use this hook to intercept streaming responses. Access response headers when the stream starts and process each chunk individually. You can modify chunk content by returning a new string, or keep the original by returning nothing. ```typescript interceptor.hook((request) => { // Response headers are available immediately when the stream starts request.response = async (response) => { console.log('Stream started, status:', response.status); }; // Intercept each chunk of the streaming response request.onStreamChunk = async (chunk) => { console.log('Chunk:', chunk.text); console.log('Raw data:', chunk.raw); console.log('Index:', chunk.index); console.log('Timestamp:', chunk.timestamp); // Return modified text to replace the chunk content return chunk.text.replace('old', 'new'); // Return void or nothing to keep the original content }; return request; }); ``` -------------------------------- ### Build Project with pnpm Source: https://github.com/arktomson/ajaxinterceptor/blob/master/README.md Builds the project for production, including all JavaScript assets. ```bash pnpm build ``` -------------------------------- ### Copy Build Output to Extension Source: https://github.com/arktomson/ajaxinterceptor/blob/master/examples/chrome-extension/README.md Copy the built library file into the `vendor` directory of the Chrome extension. ```bash cp dist/iife/index.js examples/chrome-extension/vendor/ajax-hooker.iife.js ``` -------------------------------- ### Load Unpacked Extension Source: https://github.com/arktomson/ajaxinterceptor/blob/master/examples/chrome-extension/README.md Instructions for loading the unpacked Chrome extension folder into Chrome for development. ```text examples/chrome-extension ``` -------------------------------- ### Run Tests with pnpm Source: https://github.com/arktomson/ajaxinterceptor/blob/master/README.md Executes the project's test suite. ```bash pnpm test ``` -------------------------------- ### Run Tests with Coverage Report using pnpm Source: https://github.com/arktomson/ajaxinterceptor/blob/master/README.md Runs the test suite and generates a code coverage report. ```bash pnpm test:coverage ``` -------------------------------- ### Build JavaScript Only with pnpm Source: https://github.com/arktomson/ajaxinterceptor/blob/master/README.md Builds only the JavaScript output files for the project. ```bash pnpm build:js ``` -------------------------------- ### Backward Compatibility (1.x) Source: https://github.com/arktomson/ajaxinterceptor/blob/master/README.zh-CN.md Information regarding the backward compatibility of older API methods. ```APIDOC ## Backward Compatibility (1.x) The `interceptor.xhrInterceptor` and `interceptor.fetchInterceptor` properties are retained in version 1.x for backward compatibility and are planned to be made private in version 2.x. It is recommended to use the public APIs: - `interceptor.hook(...) - `interceptor.unhook(...) - `interceptor.inject(...) - `interceptor.uninject(...) ``` -------------------------------- ### AjaxInterceptor API Source: https://github.com/arktomson/ajaxinterceptor/blob/master/README.zh-CN.md This section details the core API methods for interacting with the AjaxInterceptor instance. ```APIDOC ## AjaxInterceptor.getInstance() ### Description Gets the singleton instance of the interceptor. ### Method `AjaxInterceptor.getInstance()` ### Example ```typescript const interceptor = AjaxInterceptor.getInstance(); ``` ``` ```APIDOC ## inject(type?) ### Description Injects the interceptor, starting request interception. ### Parameters - **type** (string) - Optional. Specifies the injection type: `'xhr'` or `'fetch'`. If not specified, both are injected. ### Example ```typescript // Inject all interceptor.inject(); // Inject only XHR interceptor.inject('xhr'); // Inject only Fetch interceptor.inject('fetch'); ``` ``` ```APIDOC ## uninject(type?) ### Description Removes the interceptor, restoring original XMLHttpRequest and Fetch. ### Parameters - **type** (string) - Optional. Specifies the removal type: `'xhr'` or `'fetch'`. If not specified, both are removed. ### Example ```typescript // Remove all interceptor.uninject(); // Remove only XHR interceptor.uninject('xhr'); ``` ``` ```APIDOC ## hook(fn, type?) ### Description Adds a hook function to intercept requests. ### Parameters - **fn** (function) - The hook function, which receives the request object and should return the modified request object (or no return to keep the original request). - **type** (string) - Optional. Specifies the interception type: `'xhr'` or `'fetch'`. If not specified, both are intercepted. ### Example ```typescript // Intercept all requests interceptor.hook((request) => { console.log('Request:', request.url); return request; }); // Intercept only XHR requests interceptor.hook((request) => { console.log('XHR Request:', request.url); return request; }, 'xhr'); // Intercept only Fetch requests interceptor.hook((request) => { console.log('Fetch Request:', request.url); return request; }, 'fetch'); ``` ``` ```APIDOC ## unhook(fn?, type?) ### Description Removes a specific hook or clears all hooks. ### Parameters - **fn** (function) - Optional. If provided, removes this specific hook. If omitted, clears all hooks. - **type** (string) - Optional. Specifies `'xhr'` or `'fetch'` to clear hooks only for that type. If omitted, handles both. ### Example ```typescript const loggerHook = (request) => { console.log(request.url); return request; }; interceptor.hook(loggerHook); // Remove a specific hook interceptor.unhook(loggerHook); // Clear all fetch hooks interceptor.unhook(undefined, 'fetch'); // Clear all hooks interceptor.unhook(); ``` ``` -------------------------------- ### Fine-grained Control by Request Type Source: https://github.com/arktomson/ajaxinterceptor/blob/master/README.zh-CN.md Shows how to inject, hook, and uninject the interceptor for specific request types like 'fetch' only. ```typescript // 只注入 Fetch 拦截 interceptor.inject('fetch'); // 只拦截 Fetch 请求 interceptor.hook((request) => { request.headers.set('x-from', 'fetch-only'); return request; }, 'fetch'); // 只移除 Fetch 拦截 interceptor.uninject('fetch'); ``` -------------------------------- ### Unified Request Lifecycle: Before and After Source: https://github.com/arktomson/ajaxinterceptor/blob/master/README.md Mutate request parameters before the request is sent and define a unified response callback for both XHR and Fetch requests. ```typescript interceptor.hook((request) => { // Before request: mutate request params request.url = request.url.replace('/api/v1', '/api/v2'); request.headers.set('x-trace-id', crypto.randomUUID()); // After response: unified response callback for XHR + Fetch request.response = async (response) => { console.log('status:', response.status); }; return request; }); ``` -------------------------------- ### AjaxInterceptor.getInstance() Source: https://context7.com/arktomson/ajaxinterceptor/llms.txt Retrieves the singleton instance of the AjaxInterceptor. This is the primary way to access the interceptor's functionality, ensuring a single, globally managed instance. ```APIDOC ## AjaxInterceptor.getInstance() ### Description Get the singleton interceptor instance. This is the entry point for all interceptor operations and ensures only one global instance exists throughout the application lifecycle. ### Method `AjaxInterceptor.getInstance()` ### Example ```typescript import AjaxInterceptor from 'ajax-hooker'; // Get the singleton instance const interceptor = AjaxInterceptor.getInstance(); // The same instance is returned on subsequent calls const sameInstance = AjaxInterceptor.getInstance(); console.log(interceptor === sameInstance); // true ``` ``` -------------------------------- ### Build Types Only with pnpm Source: https://github.com/arktomson/ajaxinterceptor/blob/master/README.md Generates only the TypeScript declaration files, shared across ESM and CJS. ```bash pnpm build:types ``` -------------------------------- ### Capture and Log Response Data Source: https://github.com/arktomson/ajaxinterceptor/blob/master/README.md Sets up a response callback to log the status and data of a response. Handles both XHR and Fetch response formats. ```typescript interceptor.hook((request) => { request.response = async (response) => { console.log('Status:', response.status); // XHR uses response.response, Fetch uses response.json console.log('Data:', response.json || response.response); }; return request; }); ``` -------------------------------- ### Chain Multiple Hooks Source: https://context7.com/arktomson/ajaxinterceptor/llms.txt Execute multiple hooks sequentially to apply a series of modifications to requests. Each hook can build upon the changes made by previous ones. Ensure functions like `getToken()` are defined. ```typescript import AjaxInterceptor from 'ajax-hooker'; const interceptor = AjaxInterceptor.getInstance(); interceptor.inject(); // First hook: Authentication interceptor.hook((request) => { request.headers.set('Authorization', `Bearer ${getToken()}`); return request; }); // Second hook: Request tracking interceptor.hook((request) => { request.headers.set('X-Request-ID', crypto.randomUUID()); request.headers.set('X-Timestamp', Date.now().toString()); return request; }); // Third hook: Logging (no return needed to keep request unchanged) interceptor.hook((request) => { console.log(`Sending: ${request.method} ${request.url}`); console.log('Headers:', [...request.headers.entries()]); }); // Fourth hook: Response capture interceptor.hook((request) => { request.response = async (response) => { if (response.status >= 400) { console.error(`Error ${response.status}: ${request.url}`); } }; return request; }); ``` -------------------------------- ### Remove Hooks with `unhook` Source: https://github.com/arktomson/ajaxinterceptor/blob/master/README.md Demonstrates how to remove specific hooks or clear all hooks for XHR or Fetch requests. ```typescript const authHook = (request) => { request.headers.set('Authorization', 'Bearer token'); return request; }; interceptor.hook(authHook); // Remove a specific hook interceptor.unhook(authHook); // Clear all hooks for xhr only interceptor.unhook(undefined, 'xhr'); // Clear all hooks for both xhr and fetch interceptor.unhook(); ``` -------------------------------- ### Chain Multiple Hooks Sequentially in AjaxInterceptor Source: https://github.com/arktomson/ajaxinterceptor/blob/master/README.md Demonstrates how to apply multiple hooks in sequence to modify a request. Each hook receives the request object and can modify its headers or perform actions like logging. Hooks are executed in the order they are defined. ```typescript // First hook: add token interceptor.hook((request) => { request.headers.set('Authorization', 'Bearer token'); return request; }); // Second hook: add timestamp interceptor.hook((request) => { request.headers.set('X-Timestamp', Date.now().toString()); return request; }); // Third hook: log (no return value, keeps original request) interceptor.hook((request) => { console.log(`${request.method} ${request.url}`); }); ``` -------------------------------- ### Chrome Extension Integration (MV3) with Ajax Hooker Source: https://context7.com/arktomson/ajaxinterceptor/llms.txt Integrate Ajax Hooker into a Chrome extension (MV3) using content scripts. Ensure `ajax-hooker.iife.js` is included in your extension's files and specified in `manifest.json`. ```json // manifest.json { "manifest_version": 3, "name": "Request Interceptor", "version": "1.0", "content_scripts": [{ "matches": [""], "js": ["vendor/ajax-hooker.iife.js", "content.js"], "run_at": "document_start", "world": "MAIN" }] } ``` ```javascript // content.js const interceptor = window.AjaxHooker.getInstance(); interceptor.inject(); interceptor.hook((request) => { // Add extension identifier header request.headers.set('X-Extension', 'my-extension'); // Log all requests request.response = async (response) => { console.log(`[Extension] ${request.method} ${request.url} -> ${response.status}`); }; return request; }); ``` -------------------------------- ### Remove Hooks with unhook Source: https://github.com/arktomson/ajaxinterceptor/blob/master/README.zh-CN.md Demonstrates how to remove a specific hook function or clear all hooks for XHR, Fetch, or both. ```typescript const authHook = (request) => { request.headers.set('Authorization', 'Bearer token'); return request; }; interceptor.hook(authHook); // 移除指定钩子 interceptor.unhook(authHook); // 仅清空 xhr 的全部钩子 interceptor.unhook(undefined, 'xhr'); // 清空 xhr + fetch 的全部钩子 interceptor.unhook(); ``` -------------------------------- ### Browser IIFE Usage with Ajax Hooker Source: https://context7.com/arktomson/ajaxinterceptor/llms.txt Use this snippet to include Ajax Hooker directly in your HTML file without a bundler. Access the interceptor via the global `window.AjaxHooker` object. ```html ``` -------------------------------- ### URL Rewriting for Endpoint Switching (Dev/Prod) Source: https://context7.com/arktomson/ajaxinterceptor/llms.txt Modify request URLs to switch between different API endpoints based on the environment, such as redirecting from a production API to a local development server. ```typescript import AjaxInterceptor from 'ajax-hooker'; const interceptor = AjaxInterceptor.getInstance(); interceptor.inject(); // Endpoint switching (dev/prod environments) interceptor.hook((request) => { if (location.hostname === 'localhost') { request.url = request.url.replace( 'https://api.production.com', 'http://localhost:3000' ); } return request; }); ``` -------------------------------- ### Inject Authentication Tokens Source: https://context7.com/arktomson/ajaxinterceptor/llms.txt Automatically add authentication headers to outgoing requests. Ensure your token retrieval logic (e.g., localStorage.getItem, getAccessToken) is correctly implemented. ```typescript import AjaxInterceptor from 'ajax-hooker'; const interceptor = AjaxInterceptor.getInstance(); interceptor.inject(); // Simple token injection interceptor.hook((request) => { const token = localStorage.getItem('authToken'); if (token) { request.headers.set('Authorization', `Bearer ${token}`); } return request; }); // Conditional auth based on endpoint interceptor.hook((request) => { if (request.url.includes('/api/protected/')) { const token = getAccessToken(); request.headers.set('Authorization', `Bearer ${token}`); request.headers.set('X-Client-ID', 'my-app'); } return request; }); ``` -------------------------------- ### Request Object (AjaxInterceptorRequest) Source: https://github.com/arktomson/ajaxinterceptor/blob/master/README.md Details the structure of the request object passed to hook functions. ```APIDOC ## Request Object (AjaxInterceptorRequest) ### Description The request object received by hook functions contains the following properties: ### Properties - **type** (string) - Read-only - Request type, identifies the request source ('xhr' or 'fetch') - **method** (string) - Writable - HTTP method (GET, POST, etc.) - **url** (string) - Writable - Request URL - **headers** (Headers) - Writable - Request headers, standard [Headers](https://developer.mozilla.org/en-US/docs/Web/API/Headers) object - **data** (any) - Writable - Request body - **response** ((response: AjaxResponse) => void | Promise) - Writable - Response callback, invoked when the response is received - **onStreamChunk** ((chunk: StreamChunk) => string | void | Promise) - Writable - Streaming response hook (optional), used to intercept each chunk of a streaming response - **responseType** (XMLHttpRequestResponseType) - Writable - XHR only. Corresponds to `xhr.responseType` - **withCredentials** (boolean) - Writable - XHR only. Corresponds to `xhr.withCredentials` - **timeout** (number) - Writable - XHR only. Corresponds to `xhr.timeout` ### Interface Definition ```typescript interface AjaxInterceptorRequest { type: 'xhr' | 'fetch'; method: string; url: string; headers: Headers; data: any; response: (response: AjaxResponse) => void | Promise; onStreamChunk?: (chunk: StreamChunk) => string | void | Promise; // XHR-specific properties responseType?: XMLHttpRequestResponseType; withCredentials?: boolean; timeout?: number; } ``` ``` -------------------------------- ### Define Request and Response Hooks Source: https://github.com/arktomson/ajaxinterceptor/blob/master/examples/vanilla-xhr-fetch/index.html Hook into requests to modify headers and define a response handler to log request details and response status. The hook function receives the request object and should return it after modifications. ```javascript interceptor.hook((request) => { request.headers.set("x-demo-source", request.type); request.response = async (response) => { log(`[${request.type}]`, request.method, request.url, "->", response.status); }; return request; }); ``` -------------------------------- ### Trigger Fetch Request Source: https://github.com/arktomson/ajaxinterceptor/blob/master/examples/vanilla-xhr-fetch/index.html An event listener to trigger a Fetch API request. It logs the URL from the JSON response. Ensure the Fetch API is available in the environment. ```javascript document.getElementById("run-fetch").addEventListener("click", async () => { const res = await fetch("https://httpbin.org/anything?from=fetch"); const json = await res.json(); log("fetch result:", json.url); }); ``` -------------------------------- ### Simulate Fetch Network Errors Source: https://github.com/arktomson/ajaxinterceptor/blob/master/README.md Intercepts Fetch requests to a specific URL and simulates a network error using `mockError`. ```typescript interceptor.hook((request) => { if (request.url.includes('/api/fail')) { request.response = (response) => { response.mockError = new TypeError('Failed to fetch'); }; } return request; }, 'fetch'); ``` -------------------------------- ### Type-Specific Interception Source: https://github.com/arktomson/ajaxinterceptor/blob/master/README.zh-CN.md Demonstrates how to apply interception logic selectively to XHR or Fetch requests. ```APIDOC ## Type-Specific Interception ### Injecting specific types Control which request types (XHR or Fetch) the interceptor should manage. ### Method `interceptor.inject(type)` ### Example ```typescript // Inject only Fetch interceptor.inject('fetch'); ``` ### Hooking specific types Apply hook functions only to specific request types. ### Method `interceptor.hook(fn, type)` ### Example ```typescript // Only intercept Fetch requests interceptor.hook((request) => { request.headers.set('x-from', 'fetch-only'); return request; }, 'fetch'); ``` ### Uninjecting specific types Remove interception for specific request types. ### Method `interceptor.uninject(type)` ### Example ```typescript // Only remove Fetch interception interceptor.uninject('fetch'); ``` ``` -------------------------------- ### Streaming Response Auto-Detection Source: https://github.com/arktomson/ajaxinterceptor/blob/master/README.md Explains how the interceptor automatically detects and handles streaming responses based on Content-Type headers. ```APIDOC ## Streaming Response Auto-Detection The interceptor automatically detects streaming responses based on the `Content-Type` response header. The following types are recognized as streaming responses: - `text/event-stream` (SSE) - `application/stream+json` - `application/x-ndjson` - `application/jsonl` - `application/json-seq` When a streaming response is detected: 1. The `response` callback is invoked immediately (containing only `status`, `statusText`, `ok`, `headers`, `finalUrl`, `redirected` — no body data) 2. Stream data is passed chunk by chunk via the `onStreamChunk` hook 3. Returning a `string` from `onStreamChunk` modifies the chunk content; returning `void` or nothing keeps the original content ``` -------------------------------- ### uninject(type?) Source: https://context7.com/arktomson/ajaxinterceptor/llms.txt Removes the AjaxInterceptor, restoring native XMLHttpRequest and Fetch APIs. You can specify whether to uninject 'xhr', 'fetch', or both. ```APIDOC ## uninject(type?) ### Description Remove the interceptor and restore native XMLHttpRequest and Fetch APIs. Can target specific request types or restore both when no argument is provided. ### Method `interceptor.uninject(type?: 'xhr' | 'fetch')` ### Parameters #### Query Parameters - **type** (string) - Optional - Specifies the type of requests to restore. Can be 'xhr' or 'fetch'. If omitted, both are restored. ### Example ```typescript import AjaxInterceptor from 'ajax-hooker'; const interceptor = AjaxInterceptor.getInstance(); interceptor.inject(); // Later, remove all interception interceptor.uninject(); // Or remove only specific types interceptor.uninject('xhr'); // Only restore XMLHttpRequest interceptor.uninject('fetch'); // Only restore Fetch API ``` ``` -------------------------------- ### hook(fn, type?) Source: https://context7.com/arktomson/ajaxinterceptor/llms.txt Adds a hook function to intercept requests. Hooks can modify requests and capture responses. They are executed in the order they are added. ```APIDOC ## hook(fn, type?) ### Description Add a hook function to intercept requests. The hook receives a request object with writable properties and can optionally return the modified request. Hooks execute in the order they were added. ### Method `interceptor.hook(fn: (request: AjaxRequest) => AjaxRequest | Promise, type?: 'xhr' | 'fetch')` ### Parameters #### Path Parameters - **fn** (function) - Required - The hook function to execute. It receives an `AjaxRequest` object and should return the (potentially modified) `AjaxRequest` or a Promise resolving to it. - **type** (string) - Optional - Specifies the type of requests to hook. Can be 'xhr' or 'fetch'. If omitted, hooks apply to both. ### Request Body #### AjaxRequest Object Properties - **method** (string) - The HTTP method (e.g., 'GET', 'POST'). - **url** (string) - The request URL. - **headers** (Headers) - A `Headers` object for request headers. - **data** (any) - The request body data. - **timeout** (number) - Request timeout in milliseconds. - **withCredentials** (boolean) - Whether to send credentials. - **response** (function) - A callback function to handle the response. ### Request Example ```typescript import AjaxInterceptor from 'ajax-hooker'; const interceptor = AjaxInterceptor.getInstance(); interceptor.inject(); // Hook all requests (XHR and Fetch) interceptor.hook((request) => { console.log(`[${request.type}] ${request.method} ${request.url}`); // Modify request headers request.headers.set('Authorization', 'Bearer my-token'); request.headers.set('X-Custom-Header', 'custom-value'); // Capture response request.response = async (response) => { console.log('Status:', response.status); console.log('Data:', response.json || response.response); }; return request; }); // Hook only Fetch requests interceptor.hook((request) => { request.headers.set('X-Fetch-Only', 'true'); return request; }, 'fetch'); // Hook only XHR requests interceptor.hook((request) => { request.timeout = 5000; request.withCredentials = true; return request; }, 'xhr'); ``` ``` -------------------------------- ### Clear Log Display Source: https://github.com/arktomson/ajaxinterceptor/blob/master/examples/vanilla-xhr-fetch/index.html An event listener to clear the content of the log element. This is useful for resetting the display between tests. ```javascript document.getElementById("clear-log").addEventListener("click", () => { logEl.textContent = ""; }); ``` -------------------------------- ### AjaxResponse Object Structure Source: https://github.com/arktomson/ajaxinterceptor/blob/master/README.md Defines the structure of the AjaxResponse object, which contains properties for both XHR and Fetch API responses. ```APIDOC ## AjaxResponse Object The response object received by the response callback contains the following properties: | Property | Type | Access | Description | |----------|------|--------|-------------| | `status` | `number` | **Writable** | HTTP status code | | `statusText` | `string` | **Writable** | HTTP status text | | `headers` | `Headers` | Read-only | Response headers | | `finalUrl` | `string` | Read-only | Final URL (after redirects) | | `response` | `any` | **Writable** | XHR only. Corresponds to `xhr.response` | | `responseText` | `string` | **Writable** | XHR only. Corresponds to `xhr.responseText` | | `responseXML` | `Document \| null` | **Writable** | XHR only. Corresponds to `xhr.responseXML` | | `ok` | `boolean` | Read-only | Fetch only. Whether the request was successful (status 200-299) | | `redirected` | `boolean` | Read-only | Fetch only. Whether the request was redirected | | `json` | `any` | Read-only | Fetch only. Parsed JSON data | | `text` | `string` | Read-only | Fetch only. Response text | | `arrayBuffer` | `ArrayBuffer` | Read-only | Fetch only. Response ArrayBuffer | | `blob` | `Blob` | Read-only | Fetch only. Response Blob | | `formData` | `FormData` | Read-only | Fetch only. Response FormData | | `mockError` | `Error \| string` | **Writable** | Fetch only. Rejects the fetch promise after the real request has been sent | **Note:** For Fetch responses, `json`, `text`, `arrayBuffer`, `blob`, and `formData` are automatically parsed by the interceptor and available as properties. No need to call `.json()` or similar methods. If parsing fails, the corresponding property is `null`. ```typescript interface AjaxResponse { // Common properties status: number; // Writable statusText: string; // Writable headers: Headers; // Read-only finalUrl: string; // XHR-specific (Writable) response?: any; responseText?: string; responseXML?: Document | null; // Fetch-specific (Read-only, auto-parsed) ok?: boolean; redirected?: boolean; json?: any; text?: string; arrayBuffer?: ArrayBuffer; blob?: Blob; formData?: FormData; mockError?: Error | string; } ``` ``` -------------------------------- ### hook(fn, type?) Source: https://github.com/arktomson/ajaxinterceptor/blob/master/README.md Adds a hook function to intercept requests. The hook function receives a request object and can return a modified request. ```APIDOC ## hook(fn, type?) ### Description Add a hook function. ### Method Instance method ### Endpoint N/A ### Parameters #### Query Parameters - **fn** (function) - Required - Hook function that receives a request object and returns the modified request (can also return nothing, in which case the original request is kept unchanged) - **type** (string) - Optional - Specify 'xhr' or 'fetch' to intercept only one type. If omitted, both are intercepted. ### Request Example ```typescript // Intercept all requests interceptor.hook((request) => { console.log('Request:', request.url); return request; }); // Only XHR interceptor.hook((request) => { console.log('XHR:', request.url); return request; }, 'xhr'); // Only Fetch interceptor.hook((request) => { console.log('Fetch:', request.url); return request; }, 'fetch'); ``` ### Response None ``` -------------------------------- ### unhook(fn?, type?) Source: https://context7.com/arktomson/ajaxinterceptor/llms.txt Removes a specific hook function or clears all hooks. You can target a specific hook, a type of request, or both. ```APIDOC ## unhook(fn?, type?) ### Description Remove a specific hook function or clear all hooks. Can target specific request types or affect both when no type is specified. ### Method `interceptor.unhook(fn?: (request: AjaxRequest) => AjaxRequest | Promise, type?: 'xhr' | 'fetch')` ### Parameters #### Path Parameters - **fn** (function) - Optional - The specific hook function to remove. If omitted, all hooks for the specified type (or all types if type is also omitted) will be removed. - **type** (string) - Optional - Specifies the type of requests for which to remove hooks. Can be 'xhr' or 'fetch'. If omitted, hooks for both types are affected. ### Example ```typescript import AjaxInterceptor from 'ajax-hooker'; const interceptor = AjaxInterceptor.getInstance(); interceptor.inject(); // Define a reusable hook const authHook = (request) => { request.headers.set('Authorization', 'Bearer token'); return request; }; const loggingHook = (request) => { console.log(`Request: ${request.url}`); return request; }; // Add hooks interceptor.hook(authHook); interceptor.hook(loggingHook); // Remove a specific hook interceptor.unhook(authHook); // Clear all hooks for Fetch only interceptor.unhook(undefined, 'fetch'); // Clear all hooks for both XHR and Fetch interceptor.unhook(); ``` ``` -------------------------------- ### Add Authorization Token to Request Source: https://github.com/arktomson/ajaxinterceptor/blob/master/README.md Adds an 'Authorization' header with a Bearer token to outgoing requests. ```typescript interceptor.hook((request) => { request.headers.set('Authorization', `Bearer ${getToken()}`); return request; }); ``` -------------------------------- ### Add Hook Function Source: https://github.com/arktomson/ajaxinterceptor/blob/master/README.zh-CN.md Add a hook function to intercept and potentially modify requests. Can specify 'xhr' or 'fetch', or both by default. ```typescript // 拦截所有请求 interceptor.hook((request) => { console.log('请求:', request.url); return request; }); // 只拦截 XHR 请求 interceptor.hook((request) => { console.log('XHR 请求:', request.url); return request; }, 'xhr'); // 只拦截 Fetch 请求 interceptor.hook((request) => { console.log('Fetch 请求:', request.url); return request; }, 'fetch'); ``` -------------------------------- ### Rewrite Request URL Source: https://github.com/arktomson/ajaxinterceptor/blob/master/README.md Intercepts requests and rewrites the URL if it matches a specific pattern, useful for versioning APIs. ```typescript interceptor.hook((request) => { if (request.url.includes('/api/v1/')) { request.url = request.url.replace('/api/v1/', '/api/v2/'); } return request; }); ``` -------------------------------- ### Intercept Streaming NDJSON/SSE Responses with AjaxHooker Source: https://github.com/arktomson/ajaxinterceptor/blob/master/examples/streaming-ndjson/index.html This snippet demonstrates how to intercept streaming responses (NDJSON/SSE style) using AjaxHooker. It transforms each incoming stream chunk before it's consumed by the application code. Ensure AjaxHooker is loaded before running this code. ```javascript const interceptor = window.AjaxHooker.getInstance(); const logEl = document.getElementById("log"); function log(...args) { logEl.textContent += `${args.join(" ")}\n`; } interceptor.inject("fetch"); interceptor.unhook(undefined, "fetch"); interceptor.hook((request) => { request.response = async (response) => { log("stream started:", response.status, response.finalUrl); }; request.onStreamChunk = async (chunk) => { log("chunk", chunk.index, "len=", chunk.text.length); return chunk.text.toUpperCase(); }; return request; }, "fetch"); document.getElementById("run-stream").addEventListener("click", async () => { log("sending request..."); const response = await fetch("https://httpbin.org/stream/3"); const text = await response.text(); log("--- transformed stream body ---"); log(text); }); ``` -------------------------------- ### Define AjaxResponse Interface Source: https://github.com/arktomson/ajaxinterceptor/blob/master/README.md Defines the structure of the AjaxResponse object, detailing common properties and those specific to XHR or Fetch requests. ```typescript interface AjaxResponse { // Common properties status: number; // Writable statusText: string; // Writable headers: Headers; // Read-only finalUrl: string; // XHR-specific (Writable) response?: any; responseText?: string; responseXML?: Document | null; // Fetch-specific (Read-only, auto-parsed) ok?: boolean; redirected?: boolean; json?: any; text?: string; arrayBuffer?: ArrayBuffer; blob?: Blob; formData?: FormData; mockError?: Error | string; } ``` -------------------------------- ### AjaxInterceptorRequest Interface Source: https://github.com/arktomson/ajaxinterceptor/blob/master/README.md Defines the structure of the request object passed to hook functions. Properties like 'method', 'url', 'headers', and 'data' are writable. ```typescript interface AjaxInterceptorRequest { type: 'xhr' | 'fetch'; method: string; url: string; headers: Headers; data: any; response: (response: AjaxResponse) => void | Promise; onStreamChunk?: (chunk: StreamChunk) => string | void | Promise; // XHR-specific properties responseType?: XMLHttpRequestResponseType; withCredentials?: boolean; timeout?: number; } ``` -------------------------------- ### Trigger XMLHttpRequest (XHR) Request Source: https://github.com/arktomson/ajaxinterceptor/blob/master/examples/vanilla-xhr-fetch/index.html An event listener to trigger an XMLHttpRequest. It parses the JSON response and logs the URL. This demonstrates intercepting traditional XHR requests. ```javascript document.getElementById("run-xhr").addEventListener("click", () => { const xhr = new XMLHttpRequest(); xhr.open("GET", "https://httpbin.org/anything?from=xhr"); xhr.onload = () => { const data = JSON.parse(xhr.responseText); log("xhr result:", data.url); }; xhr.send(); }); ```