diff --git a/.babelrc.js b/.babelrc.js
new file mode 100644
index 000000000..c5154858d
--- /dev/null
+++ b/.babelrc.js
@@ -0,0 +1,14 @@
+module.exports = {
+ babelrcRoots: ["packages/*"],
+ plugins: ["babel-plugin-transform-vite-meta-env"],
+ presets: [
+ "@babel/preset-env",
+ "@babel/preset-typescript",
+ [
+ "@babel/preset-react",
+ {
+ runtime: "automatic",
+ },
+ ],
+ ],
+};
diff --git a/.cursor/mcp.json b/.cursor/mcp.json
new file mode 100644
index 000000000..092cb736d
--- /dev/null
+++ b/.cursor/mcp.json
@@ -0,0 +1,7 @@
+{
+ "mcpServers": {
+ "nx-mcp": {
+ "url": "http://localhost:9057/sse"
+ }
+ }
+}
\ No newline at end of file
diff --git a/.cursor/rules/documentation.mdc b/.cursor/rules/documentation.mdc
new file mode 100644
index 000000000..0c82c40d1
--- /dev/null
+++ b/.cursor/rules/documentation.mdc
@@ -0,0 +1,396 @@
+---
+description: Best practices for writing documentation approach
+globs: **/*.mdx, **/*.md
+alwaysApply: false
+---
+
+# Documentation Best Practices
+
+## General Guidelines
+
+- We're using docusaurus and its features to build our documentation
+- Keep documentation clear, concise, and up-to-date
+- Use consistent language and tone throughout
+- Write for your audience (developers, end-users, etc.)
+- Follow a logical structure with proper headings
+- Use active voice and present tense
+- Include examples for complex concepts
+- Limit each document to a single topic or concern
+- Split # and ## headings with --- separator
+
+## Inspirations
+
+The documentation approach in this project is inspired by the best practices found in the React and Stripe
+documentation. Both of these projects are renowned for their:
+
+- **Clarity and Simplicity**: Information is presented in a clear, concise, and approachable manner, making it easy for
+ developers of all experience levels to understand and use.
+- **Logical Structure**: Content is organized with a strong hierarchy, intuitive navigation, and consistent formatting,
+ helping users quickly find what they need.
+- **Comprehensive Examples**: Both documentations provide real-world, copy-pastable code examples that are always
+ up-to-date and verified against the latest version of the library.
+- **Developer-Centric Focus**: The needs of developers are prioritized, with detailed guides, API references, and
+ troubleshooting sections that address common use cases and pain points.
+- **Visual Aids and Interactivity**: Use of diagrams, interactive elements, and visual cues to enhance understanding of
+ complex concepts.
+
+By drawing inspiration from React and Stripe, this project aims to deliver documentation that is not only technically
+accurate but also highly usable, discoverable, and enjoyable for all users.
+
+
+## Structure
+
+1. Title
+2. Description
+3. Admonition with types:
+ - :::tip is good for docs and "Purpose" (Purpose - should contain numbered list of features with bold parts of text)
+ - :::secondary for guides and "What you'll learn"
+ - :::success for the end of guide, or summaries of what you learnt
+ - :::caution / :::warning for important and possibly unsafe details
+ - :::danger for places that can cause errors or unexpected behavior
+This admonition should usually have the numbered list
+1. Other sections...
+
+## Markdown Usage
+
+- Use proper heading hierarchies (H1 > H2 > H3)
+- Under each heading there should be some description or text
+- Apply consistent formatting for code blocks with language specification
+- Use lists for sequential or grouped information
+- Utilize tables for structured data comparison
+- Include properly sized and labeled images when helpful
+- Use blockquotes for important notes or warnings
+- Add horizontal rules to separate major sections
+- Use the import directive syntax `(@import {packageName} {componentName} {content type})` to selectively include
+ essential information from autogenerated documentation.
+- Use admonitions for warnings, notes, tips, and important information, it is important to leave empty space around it:
+##### Bad use of admonitions
+```md
+:::note Some admonition title
+Some admonition description
+:::
+```
+#### Good use of admonitions
+```md
+:::note Some admonition title
+
+Some admonition description
+
+:::
+```
+
+## Importer Usage Guide
+
+The documentation system includes a powerful import directive that allows embedding auto-generated API documentation
+into markdown files. This helps maintain consistency between code and documentation.
+
+### Basic Syntax
+
+```
+(@import {packageName} {componentName} {contentType})
+```
+
+- **packageName**: Name of the package from `/packages` directory (e.g., `core`, `client`, `react`)
+- **componentName**: Type of component to import (e.g., `class`, `function`, `interface`, `type`)
+- **contentType**: What aspect of the component to import
+
+### Finding Component Names
+
+Component names for import directives can be found by browsing the `/documentation/docs/api` directory. Each file in
+this directory represents a component from the codebase, and the filename corresponds to the component name that should
+be used in the import directive. This makes it easy to discover available components for documentation imports.
+
+### Available Content Types
+
+| Content Type | Description |
+| -------------- | ------------------------------------ |
+| definition | Complete definition of the component |
+| npm | NPM installation information |
+| import | Import statement for the component |
+| details | Detailed component information |
+| description | Component description from JSDoc |
+| generics | Generic parameters information |
+| method | Single method documentation |
+| methods | All methods documentation |
+| name | Component name only |
+| parameters | Function parameters |
+| preview | Brief component preview |
+| properties | Object/interface properties |
+| returns | Return value information |
+| returnsPreview | Brief return value preview |
+| signature | Function/method signature |
+| sources | Source code information |
+| type | Type information |
+
+### Usage
+
+(@import core Client import) (@import core Client description)
+
+### Best Practices
+
+- Only import essential information to keep documentation concise
+- Use preview content types for overview sections
+- Use specific content types (parameters, returns, etc.) for detailed documentation
+- Combine multiple imports to create comprehensive but organized documentation
+- Always verify that imported content appears correctly in the rendered documentation
+
+## Documentation Links
+
+When creating links between documentation pages, follow these guidelines to ensure consistency and maintainability:
+
+### Link Types
+
+The documentation supports two primary ways to create links between pages:
+
+1. **Markdown Links**
+
+ ```md
+ [Link Text](mdc:documentation/docs/path/to/file.md)
+ ```
+
+ - Always use relative paths from the root
+ - All paths should start with `/documentation/docs/`
+ - Use descriptive link text that indicates the target content
+
+2. **LinkCard Component**
+
+ ```jsx
+
+ ```
+
+ - Use for featured links that deserve visual emphasis
+ - Use different types depending on the link source - guides | docs | integrations | promo | api
+ - Provide a clear title and concise description
+ - Use for the links taking whole paragraph
+ - Follow the same path rules as markdown links
+
+### Best Practices for Links
+
+- Ensure all links lead to files within the `/documentation/docs` directory
+- Verify links work correctly after documentation structure changes
+- Use LinkCards for navigation between major sections or to highlight important content
+- Use standard markdown links for inline references within text
+- Keep link text descriptive and meaningful (avoid "click here" or "read more")
+- Consider adding a brief context about what the reader will find in the linked document
+
+### Link Path Requirements
+
+- All link paths must follow this pattern: `/documentation/docs/[path]/[filename]`
+- Never omit the file extension, as this can break documentation navigation and versioning
+- This applies to both standard Markdown links and LinkCard component paths
+
+## Documentation Types and Locations
+
+- The project features three distinct types of documentation:
+
+ 1. **Core Documentation** (`/documentation/docs`)
+ - Covers overall ideas behind modules
+ - Provides limited but focused examples
+ - Explains the purpose, important features, methods and functionalities
+ - Contains links to other important documentation sections (guides, API references)
+ 2. **Guides** (`/documentation/docs/guides`)
+ - Problem-focused with detailed explanations
+ - Provides complete code examples with syntax highlighting
+ - Includes step-by-step instructions for implementation
+ - Addresses specific use cases and solutions
+ 3. **API References** (`/documentation/docs/api`)
+ - Autogenerated documentation that cannot be directly edited
+ - To enhance API docs, add JSDoc comments to the relevant code in package files
+ - Document entities, modules, parameters, and other code elements at their source
+
+- Essential information for the packages are: how to install, how to use, what it's doing and how is it helpful
+- Each entity from the packages should have it's Purpose section
+
+## API Documentation
+
+- Document all public APIs with consistent formatting
+- Include parameter descriptions, types, and default values
+- Provide return value information
+- Add examples showing typical usage
+- Document possible errors and edge cases
+- Use JSDoc or similar standards for code documentation
+- Keep method documentation close to its implementation
+
+## README Files
+
+- Include a clear project description
+- Document installation and setup instructions
+- Provide getting started examples
+- List prerequisites and dependencies
+- Include troubleshooting sections for common issues
+- Add references to additional documentation
+- Maintain contributing guidelines and code of conduct
+
+## Documentation Organization
+
+- Create a logical hierarchy of documentation
+- Implement proper navigation between related documents
+- Include a search feature if documentation is extensive
+- Create an index or table of contents for larger docs
+- Group related documentation together
+- Use consistent filenames and folder structure
+- Link to related documentation when appropriate - they always start with "/docs" and should lead to the .md or .mdx
+ file to keep the versioning abilities
+
+## Interactive Documentation
+
+- Implement collapsible sections for complex documentation
+- Use tabs to organize related but separate content
+- Add interactive diagrams to explain complex workflows - could be with mermaid or other
+- Include working demos of components and features
+- Enable dark/light mode toggle for documentation
+- Consider implementing interactive tutorials for key features
+
+## Accessibility
+
+- Use descriptive link text (avoid "click here")
+- Add alt text to all images
+- Create scannable content with proper headings
+- Write in plain language, avoiding jargon when possible
+- Define acronyms and technical terms
+- Ensure documentation is responsive for mobile devices
+
+## Code Examples
+
+- Provide complete, working code examples
+- Avoid large code example blocks or mixing multiple examples in a single snippet
+- Use syntax highlighting with proper language tags
+- Make examples copy-pastable when possible
+- Include comments to explain complex parts
+- Show both basic and advanced use cases
+- Update examples when the API changes
+- Test all code examples to ensure they work
+- Ensure examples are highly accessible by using appropriate syntax highlighting, clear formatting, code diffs and
+ sufficient color contrast for improved readability
+
+- **Keep examples brief and focused** - Each example should demonstrate a single concept or feature rather than trying
+ to showcase multiple capabilities at once
+- **Base examples on actual code** - All code examples must be based on the actual implementation in the `/packages`
+ directory
+- **Do not create hypothetical examples** - Don't create examples that haven't been verified against the actual codebase
+- **Reference existing implementations** - If unsure how something works, examine the source code in the packages
+ directory first
+- **Request clarification when needed** - If you need more information about implementation details, ask for specific
+ paths or reference code
+- **Test all examples** - Verify that code examples actually work with the current library version before including them
+- **Include imports** - Always show the necessary imports for the examples to work
+
+### Code Example Accuracy Requirements
+
+- **Never hallucinate code examples** - All examples must be based on real, working code from the `/packages` directory
+- **Examine the source code first** - Before writing an example, thoroughly review the actual implementation in the
+ codebase, search for the tests which can give you better idea on how something works
+- **Reproduce real-world usage patterns** - Follow the patterns and conventions used in the actual codebase
+- **Respect types and signatures** - Ensure all parameter types and return values match the actual implementation
+- **When in doubt, ask** - If you're unsure how a feature works, ask for specific paths to reference code instead of
+ guessing
+- **Document limitations** - Be clear about any constraints or edge cases in the implementation
+- **Indicate version compatibility** - Note which versions of the library the example works with
+
+### Example Verification Process
+
+1. Locate the relevant code in the `/packages` directory, each have `__tests__` directory with many examples of the code
+2. Understand the implementation and API surface
+3. Create a minimal working example that demonstrates the feature
+4. Test the example to ensure it works as expected
+5. Document any dependencies or prerequisites
+6. Include complete import statements and configuration
+7. Add explanatory comments for complex parts
+8. Verify the example against the latest version of the library
+
+### Code Highlighting in Examples
+
+To emphasize specific lines or sections in code examples, use the following comment markers:
+
+```js
+// highlight-start
+// ... code to highlight ...
+// highlight-end
+
+// highlight-next-line
+const important = true;
+```
+
+- Place `// highlight-start` before the code you want to highlight and `// highlight-end` after.
+- Use `// highlight-next-line` to highlight only the line immediately following the comment.
+- This works for JavaScript, TypeScript, and other languages that support `//` comments. For other languages, use the
+ appropriate comment syntax (e.g., `#` for Python).
+- Use highlighting sparingly to draw attention to the most important parts of an example, such as key logic,
+ configuration, or changes.
+- Do not use highlighting for entire code blocks unless every line is essential.
+- Always ensure highlighted code is accurate and up-to-date with the actual implementation.
+
+### Red Highlighting for Errors
+
+To visually indicate lines that will cause an error (red highlight), use the following comment:
+
+```js
+// error-next-line
+throw new Error(1);
+// Throws the Error(1)
+
+// error-start
+function error() {
+ throw new Error(1);
+}
+// error-end
+// Throws the Error(1)
+```
+
+- Place `// error-...` directly above the line that should be highlighted in red as an error.
+- Use this only for lines that are expected to throw or demonstrate incorrect usage.
+- This helps readers quickly identify problematic code in examples.
+- Leave helpful comments with error details under it
+
+### Showing Code Diffs in Examples
+
+To illustrate code changes (diffs) in examples, use the following comment markers:
+
+```js
+// diff-add-next-line
+const newValue = 2;
+
+// diff-remove-next-line
+const oldValue = 1;
+
+// diff-add-start
+const foo = 1;
+const bar = 2;
+// diff-add-end
+
+// diff-remove-start
+const oldFoo = 0;
+const oldBar = 0;
+// diff-remove-end
+```
+
+- Use `// diff-remove-...` to indicate a line that should be shown as removed in a diff.
+- Use `// diff-add-...` to indicate a line that should be shown as added in a diff.
+- Place the comments directly above the relevant lines.
+- This helps readers quickly understand what has changed between code versions or in upgrade guides.
+- Only use these markers when demonstrating code changes, migrations, or upgrade steps.
+
+### Creating Live Code Examples
+
+To provide interactive, live-editable code examples in the documentation, use the `live` option in your code block:
+
+```tsx live
+function Example() {
+ return
Hello, world!
;
+}
+```
+
+```ts live
+console.log(123);
+```
+
+- Add `live` after the language identifier (e.g., `{lang} live`) to enable live editing and preview.
+- Use this for React or TypeScript code that benefits from interactive demonstration.
+- Keep live examples minimal and focused on a single concept.
+- Ensure all live examples are functional and error-free.
+- Only use live examples where interactivity adds value for the reader.
diff --git a/.cursor/rules/hyper-fetch-react.mdc b/.cursor/rules/hyper-fetch-react.mdc
new file mode 100644
index 000000000..e70f873ee
--- /dev/null
+++ b/.cursor/rules/hyper-fetch-react.mdc
@@ -0,0 +1,324 @@
+---
+description:
+globs: *.tsx
+alwaysApply: false
+---
+
+# Hyper Fetch - Best Practices for React
+
+This document outlines the best practices for using hyper-fetch in React applications, covering various aspects such as
+code organization, performance considerations, security, and testing. Following these guidelines ensures consistency,
+maintainability, and optimal usage of HyperFetch's features.
+
+## 1. Code Organization and Structure
+
+### Directory Structure Best Practices
+
+- **Feature-based Organization:** Group hyper-fetch requests and related components within feature-specific directories.
+ This improves modularity and maintainability.
+
+```
+ src/
+ ├── features/
+ │ ├── users/
+ │ │ ├── components/
+ │ │ │ ├── user-list.tsx
+ │ │ │ └── user-details.tsx
+ │ │ ├── api/
+ │ │ │ └── users-api.ts
+ │ │ └── types/
+ │ │ └── user.ts
+ │ ├── products/
+ │ └── ...
+ ├── ...
+
+```
+
+- **Dedicated API Service Layer:** Abstract API interaction logic into separate modules. This allows for easier testing
+ and decoupling of components from specific API implementations. Consider using a dedicated `api` directory within each
+ feature.
+
+### File Naming Conventions
+
+- **Consistent Naming:** Follow a consistent naming convention for hyper-fetch hooks. Prefix requests with method like
+ `get` | `create` | `update` | `delete` and postfix with `Request` to clearly indicate their purpose (e.g.,
+ `getUserRequest`, `createNoteRequest`).
+
+- **Descriptive Names:** Use descriptive names for files and variables to improve code readability. For example,
+ `getUsersRequest.ts` is more informative than `usersRequest.ts`.
+
+---
+
+---
+
+## 2. Common Patterns and Anti-patterns
+
+### 2.1 Design Patterns Specific to hyper-fetch
+
+- **Custom Hooks for Data Fetching:** As highlighted earlier, encapsulating hyper-fetch logic within custom hooks. This
+ promotes reusability and separation of concerns. These hooks will typically return the result of a `useQuery` or
+ `useMutation` call.
+
+- **Optimistic Updates:** Implement optimistic updates to improve perceived performance. This involves updating the UI
+ before the API request completes, and then reverting the changes if the request fails. hyper-fetch provides utilities
+ like `onMutate` to handle this.
+
+- **Pessimistic Updates:** Update the UI only after a successful response from the API. Simpler to implement but
+ provides a less snappy user experience.
+
+### 2.2 Recommended Approaches for Common Tasks
+
+- **Prefetching Data:** Prefetch data for routes or components that the user is likely to visit next. This can
+ significantly improve the user experience. Use `request.send()`.
+
+- **Dependent Queries:** Fetch data based on the result of a previous query. Use the `enabled` option in `useQuery` to
+ conditionally execute queries.
+
+ ```typescript
+ const { data: user } = useFetch(getUser);
+ const { data: posts } = useFetch(getPosts.setParams({ userId: user?.id }), { disabled: !user });
+ ```
+
+### 2.3 Anti-patterns and Code Smells to Avoid
+
+- **Directly Calling API in Components:** Avoid making API calls directly within components. This makes testing
+ difficult and tightly couples components to specific API implementations.
+
+- **Ignoring Error Handling:** Always handle errors properly. Display user-friendly error messages and provide options
+ for retrying requests.
+
+- **Over-fetching Data:** Fetch only the data that is required by the component. Use GraphQL or API query parameters to
+ reduce the amount of data transferred.
+
+- **Deeply Nested Queries:** Avoid deeply nesting queries, as this can lead to performance issues and make the code
+ difficult to understand. Consider combining queries or using a different approach.
+
+### 2.4 State Management Best Practices
+
+- **Local vs. Global State:** Determine whether data should be stored in local component state or in a global state
+ management solution. Use local state for component-specific data and global state for data that needs to be shared
+ across multiple components.
+
+- **hyper-fetch as a State Manager:** Leverage hyper-fetch's built-in caching and state management capabilities. Avoid
+ using external state management libraries for data that is already managed by hyper-fetch.
+
+### 2.5 Error Handling Patterns
+
+- **Centralized Error Handling:** Implement centralized error handling to provide consistent error messages and logging.
+
+- **Retry Logic:** Implement retry logic to automatically retry failed requests. hyper-fetch provides options for
+ configuring retry behavior.
+
+- **Error Boundaries:** Use Error Boundaries to catch errors that occur during rendering. This prevents the entire
+ application from crashing.
+
+## 3. Performance Considerations
+
+### 3.1 Optimization Techniques - Hooks
+
+- **Query Invalidation:** Invalidate queries when data changes. This ensures that the UI is always up-to-date.
+
+- **Stale-While-Revalidate:** Use the `staleTime` and `cacheTime` options to configure how long data should be
+ considered fresh. `Stale While Revalidate` allows the UI to display cached data while fetching fresh data in the
+ background. This can be passed to the hook like: `useFetch(request, { revalidate: true })`
+
+- **Window Focus Refetching:** Configure refetching on window focus to keep data fresh when the user switches back to
+ the application.
+
+- **Polling/Refetch Intervals:** Use `refreshTime` to periodically refetch data. This is useful for data that changes
+ frequently.
+
+### 3.2 Memory Management
+
+- **Query Cache Management:** Understand how hyper-fetch manages its cache. Configure the `staleTime` option to control
+ how long data is stored in the cache.
+
+- **Garbage Collection:** Ensure that unused queries are garbage collected properly. Use the `cacheTime` option to
+ configure how long inactive queries should be kept in the cache.
+
+### 3.3 Rendering Optimization
+
+- **Memoization:** Use `React.memo` to prevent unnecessary re-renders of components. This is especially important for
+ components that display data fetched from hyper-fetch.
+
+- **Virtualization:** Use virtualization techniques (e.g., `react-window`, `react-virtualized`) to efficiently render
+ large lists of data.
+
+### 3.4 Bundle Size Optimization
+
+- **Tree Shaking:** Ensure that your build process is configured for tree shaking. This removes unused code from the
+ final bundle.
+
+- **Code Splitting:** As mentioned earlier, use code splitting to reduce the initial load time.
+
+### 3.5 Lazy Loading Strategies
+
+- **Lazy Load Components:** Use `React.lazy` to lazy load components that are not immediately needed.
+
+- **Lazy Load Data:** Fetch data only when it is needed. Use dependent queries to fetch data based on user interactions.
+
+## 4. Security Best Practices
+
+### Common Vulnerabilities and How to Prevent Them
+
+- **Cross-Site Scripting (XSS):** Sanitize user input to prevent XSS attacks. Use a library like DOMPurify to sanitize
+ HTML.
+
+- **Cross-Site Request Forgery (CSRF):** Implement CSRF protection to prevent attackers from performing actions on
+ behalf of the user. Use a library or framework that provides CSRF protection.
+
+- **Injection Attacks:** Protect against injection attacks by validating user input and using parameterized queries.
+
+### Input Validation
+
+- **Client-Side Validation:** Implement client-side validation to provide immediate feedback to the user.
+
+- **Server-Side Validation:** Always validate user input on the server-side to prevent malicious data from being stored
+ in the database.
+
+### Authentication and Authorization Patterns
+
+- **JSON Web Tokens (JWT):** Use JWTs for authentication. Store the JWT in a secure cookie or in local storage (with
+ caution). Use `httpOnly` flag on cookies containing JWTs when possible to prevent client-side script access.
+
+- **Role-Based Access Control (RBAC):** Implement RBAC to control access to different parts of the application. Use
+ middleware or custom hooks to check user roles.
+
+### Data Protection Strategies
+
+- **Encryption:** Encrypt sensitive data at rest and in transit. Use HTTPS to encrypt data in transit. Encrypt sensitive
+ data in the database.
+
+- **Data Masking:** Mask sensitive data in logs and reports. This prevents sensitive data from being exposed to
+ unauthorized users.
+
+### Secure API Communication
+
+- **HTTPS:** Use HTTPS for all API communication. This encrypts data in transit and prevents eavesdropping.
+
+- **API Rate Limiting:** Implement API rate limiting to prevent abuse.
+
+- **CORS:** Configure CORS properly to prevent cross-origin requests from unauthorized domains.
+
+## 5. Testing Approaches
+
+### Unit Testing Strategies
+
+- **Test Custom Hooks:** Unit test custom hyper-fetch hooks to ensure they are working correctly. Mock the API calls
+ using libraries like `msw` (Mock Service Worker).
+
+- **Test Components in Isolation:** Unit test components in isolation to ensure they render correctly and handle user
+ interactions properly. Use libraries like `react-testing-library`.
+
+### Integration Testing
+
+- **Test Data Flow:** Integration test the data flow between components and APIs. Verify that data is fetched correctly
+ and displayed properly.
+
+- **Test Error Handling:** Integration test error handling scenarios to ensure that errors are handled properly.
+
+### End-to-End Testing
+
+- **Simulate User Interactions:** Use end-to-end testing frameworks like Cypress or Playwright to simulate user
+ interactions and verify that the application is working correctly from the user's perspective.
+
+- **Test Critical Paths:** Focus on testing critical user flows, such as login, registration, and checkout.
+
+### Test Organization
+
+- **Colocate Tests with Components:** Colocate tests with the components they are testing. This makes it easier to find
+ and maintain tests.
+
+- **Use Descriptive Test Names:** Use descriptive test names to clearly indicate what each test is verifying.
+
+### Mocking and Stubbing
+
+- **Build-in:** Use built in abilities of HyperFetch to mock requests.
+
+```ts
+const request = client.createRequest()({ endpoint: "shared-base-endpoint" });
+
+// Set mock is the only method that modify reference
+request.setMock(
+ () => {
+ // Data part
+ return {
+ data: { mocking: "is fun" },
+ status: 200,
+ };
+ },
+ {
+ // Config part
+ requestTime: 40,
+ responseTime: 60,
+ totalUploaded: 1000,
+ totalDownloaded: 1000,
+ },
+);
+```
+
+- **Mock API Calls:** Use mocking libraries like `msw` to mock API calls during testing. This allows you to test
+ components in isolation without relying on a real API.
+
+- **Stub External Dependencies:** Stub external dependencies to isolate components and make tests more predictable.
+
+## 6. Common Pitfalls and Gotchas
+
+- **Forgetting to Invalidate Queries:** Failing to invalidate queries when data changes can lead to stale data being
+ displayed in the UI.
+
+- **Incorrect Cache Configuration:** Incorrectly configuring the `cacheTime` and `staleTime` options can lead to
+ performance issues or stale data.
+
+- **Not Handling Errors Properly:** Not handling errors properly can lead to unexpected behavior and a poor user
+ experience.
+
+- **Over-relying on Default Configuration:** Customizing hyper-fetch to match specific needs is essential.
+
+- **Ignoring Devtools:** The hyper-fetch devtools are invaluable for debugging and understanding what is happening under
+ the hood.
+
+## 7. Tooling and Environment
+
+### 7.1 Recommended Development Tools
+
+- **VS Code:** Use VS Code with extensions like ESLint, Prettier, and TypeScript to improve developer productivity.
+
+- **React Developer Tools:** Use the React Developer Tools browser extension to inspect React components and state.
+
+- **Hyper Fetch Devtools - HyperFlow:** Use the HyperFlow Devtools to inspect the hyper-fetch cache, network and track
+ query and mutation status.
+
+### 7.2 Build Configuration
+
+- **Webpack or Parcel:** Use a bundler like Webpack or Parcel to bundle your code for production. Configure the bundler
+ for tree shaking and code splitting.
+
+- **Babel:** Use Babel to transpile your code to older versions of JavaScript. This ensures that your code is compatible
+ with older browsers.
+
+### 7.3 Linting and Formatting
+
+- **ESLint:** Use ESLint to enforce coding standards and prevent errors. Install dedicated linter package to avoid
+ common typescript issues. `@hyper-fetch/eslint`
+
+- **Prettier:** Use Prettier to automatically format your code. This ensures that your code is consistently formatted
+ and easy to read.
+
+### 7.4 Deployment Best Practices
+
+- **CDN:** Use a CDN to serve static assets. This improves performance and reduces the load on your server.
+
+- **Caching:** Configure caching properly on your server and CDN. This reduces the number of requests to your server and
+ improves performance.
+
+### 7.5 CI/CD Integration
+
+- **Automated Testing:** Integrate automated testing into your CI/CD pipeline. This ensures that your code is tested
+ automatically before it is deployed.
+
+- **Automated Deployment:** Automate the deployment process to reduce the risk of errors and improve efficiency.
+
+```
+
+```
diff --git a/.cursor/rules/hyper-fetch.mdc b/.cursor/rules/hyper-fetch.mdc
new file mode 100644
index 000000000..386ab00cf
--- /dev/null
+++ b/.cursor/rules/hyper-fetch.mdc
@@ -0,0 +1,277 @@
+---
+description:
+globs:
+alwaysApply: true
+---
+
+# Hyper Fetch Best Practices
+
+This document outlines the best practices for using hyper-fetch in React applications, covering various aspects such as
+code organization, performance considerations, security, and testing. Following these guidelines ensures consistency,
+maintainability, and optimal usage of HyperFetch's features.
+
+## Core Concepts
+
+HyperFetch is a powerful data-exchange framework designed for type-safety and ease of use. The main components you will
+interact with are:
+
+- **`Client`**: The central point of configuration for all requests. It holds URL of server, all modules like Cache,
+ Dispatchers, it is builder of Requests (`createRequest()({...})`)
+- **`Request`**: A class that defines a specific API endpoint, including its method, parameters, and data transformation
+ logic - everything typesafe (response, payload, params, query params, endpoint string etc)
+
+- **`useFetch` (React)**: A React hook that executes a request and provides the state of the request (data, error,
+ loading).
+- **`useSubmit` (React)**: A React hook that executes a request on call (for example button click) and provides the
+ state of the request (data, error, loading).
+
+- **`Adapters`**: Pluggable modules that handle the actual data fetching logic (e.g., `axios`, `graphql`, `firebase`).
+
+## 1. Client Configuration
+
+The `Client` instance should be created and configured once, then exported for use throughout the application.
+
+Use the `createClient` from `@hyper-fetch/core`.
+
+### Best Practices
+
+- **Singleton Client**: Create a single `Client` instance for your application to ensure consistent configuration.
+- **Base URL**: Always configure the `url` on the client. Avoid hardcoding base URLs in individual requests.
+- **Feature Configuration**: Configure features like `cache`, `queue`, and `storage` at the client level.
+
+#### Example:
+
+```typescript
+import { createClient } from "@hyper-fetch/core";
+
+export const client = createClient({
+ url: "https://api.example.com",
+});
+```
+
+## 2. Request Definition
+
+Requests should be defined in a structured and reusable way.
+
+### Best Practices
+
+- **Typed Requests**: Always define the types for request parameters, response data, and errors. This is the core
+ strength of HyperFetch.
+- **Request Factory**: Use functions to create requests. This allows for dynamic parameters and keeps the code clean.
+- **Colocation**: Keep requests related to a specific feature or data model grouped together.
+- **Error Handling**: Define error types for requests to handle API errors gracefully.
+- **Data Transformation**: Use `setResponseMapper` to transform the raw API response into the desired data structure.
+
+#### Examples:
+
+##### All Generic Types
+
+```ts
+const request = client.createRequest<{
+ // what we get in response
+ response: SomeData;
+ // What we send to backend
+ payload: SomePayload;
+ // Adds ability to specify query params
+ queryParams?: { search?: string };
+ // It will extend global error and add ability to specify errors for particular endpoint only
+ error: ZodValidationErrors;
+}>()({
+ endpoint: "/some-endpoint",
+ method: "GET",
+});
+```
+
+##### example of static params passed with method
+
+```ts
+import { client } from "./client"; // Import the configured client
+
+interface User {
+ id: number;
+ name: string;
+}
+
+const getUser = client.createRequest<{ response: User }>()({
+ endpoint: "/users/:userId",
+ method: "GET",
+});
+
+// Using the request with the client
+const { data, error, success, extra, responseTime, requestTime } = getUser
+ .setParams({ userId: 1 }) // taken from endpoint string `:userId`
+ .send();
+```
+
+##### dynamicly pass the params to send({ }) and use all of the callbacks
+
+```ts
+import { client } from "./client"; // Import the configured client
+
+interface User {
+ id: number;
+ name: string;
+}
+
+const getUser = client.createRequest<{ response: User }>()({
+ endpoint: "/users/:userId",
+ method: "GET",
+});
+
+// Using the request with the client
+const { data, error, success, extra, responseTime, requestTime } = getUser.send({
+ // pass params dynamically
+ params: { userId: 1 },
+
+ onBeforeSent: ({ response, requestId }) => {
+ console.log(`Request ${requestId} has settled. Final response:`, response);
+ // Called right before the request is sent—useful for quickly accessing the requestId for tracking or logging
+ },
+ onStart: ({ requestId, request }) => {
+ console.log(`Request ${requestId} has started.`);
+ // Called when the request is started—useful for showing a loading indicator
+ },
+ onUploadProgress: ({ progress, timeLeft, sizeLeft, total, loaded, startTimestamp, request, requestId }) => {
+ console.log(`Request ${requestId} upload progress:`, progress);
+ // Called when the upload progress is updated—useful for showing a progress bar
+ },
+ onDownloadProgress: ({ progress, timeLeft, sizeLeft, total, loaded, startTimestamp, request, requestId }) => {
+ console.log(`Request ${requestId} download progress:`, progress);
+ // Called when the download progress is updated—useful for showing a progress bar
+ },
+ onResponse: ({ response, requestId }) => {
+ console.log(`Request ${requestId} finished with data:`, response.data);
+ // Called when the request succeeds—useful for processing successful data
+ },
+ onRemove: ({ request, requestId }) => {
+ console.log(`Request ${requestId} removed.`);
+ // Called when the request is removed—useful for cleaning up
+ },
+});
+```
+
+## 3. Component Usage (React)
+
+When using HyperFetch with React, follow these guidelines for the `useFetch` hook.
+
+### Best Practices
+
+- **Hook Usage**: Use the `useFetch` hook to bind requests to your components' lifecycle.
+- **State Management**: Rely on the `data`, `error`, and `loading` states returned by `useFetch`. Avoid creating extra
+ state variables to track this.
+- **Dependencies**: Use the `dependencies` array in `useFetch` to automatically re-fetch data when component props or
+ other state changes.
+- **Manual Fetching**: The `revalidate` function returned by `useFetch` can be used to manually trigger a re-fetch.
+
+#### Example:
+
+```tsx
+import { useFetch } from "@hyper-fetch/react";
+import { client } from "./client";
+import { getUser } from "./requests";
+
+function UserProfile({ userId }) {
+ const { data, loading, error, extra, success, responseTime, requestTime, onSuccess, onError, onFinished } = useFetch(
+ client.request(getUser).setParams({ userId }),
+ );
+
+ onSuccess(({ response, request }) => {
+ console.log(response, request);
+ });
+
+ onError(({ response, request }) => {
+ console.log(response, request);
+ });
+
+ onFinished(({ response, request }) => {
+ console.log(response, request);
+ });
+
+ if (loading) return Loading...
;
+ if (error) return Error loading user!
;
+ if (!data) return null;
+
+ return {data.name} ;
+}
+```
+
+```tsx
+import { useFetch } from "@hyper-fetch/react";
+import { client } from "./client";
+import { createUser } from "./requests";
+
+function CreateUser({ userId }) {
+ const {
+ submit,
+ data,
+ submitting,
+ error,
+ extra,
+ success,
+ responseTime,
+ requestTime,
+ onSubmitSuccess,
+ onSubmitError,
+ onSubmitFinished,
+ } = useSubmit(client.request(createUser).setParams({ userId }));
+
+ onSubmitSuccess(({ response, request }) => {
+ console.log(response, request);
+ });
+
+ onSubmitError(({ response, request }) => {
+ console.log(response, request);
+ });
+
+ onSubmitFinished(({ response, request }) => {
+ console.log(response, request);
+ });
+
+
+ return submit()}>Create user;
+}
+```
+
+## 4. Feature Usage
+
+HyperFetch offers powerful features that should be used consistently.
+
+### Caching
+
+- **Enable on Client**: Enable caching on the `Client` instance for global caching.
+- **Per-Request Cache**: You can override the client's cache setting on individual requests.
+- **Cache Invalidation**: Use `client.cache.invalidate` to manually invalidate cached data when mutations occur.
+
+### Queuing
+
+- **Offline Support**: Use queuing to support offline functionality. Requests will be queued and sent when the
+ connection is restored.
+- **Request Prioritization**: Configure request priorities on the client to control the order of execution.
+
+### Persistence
+
+- **Local Storage**: Use `storage` with a `localStorage` adapter to persist data across sessions. This is useful for
+ offline-first applications.
+
+## 5. Adapters
+
+Adapters are responsible for the actual HTTP requests. By default HyperFetch uses the HTTP adapter. You may not need to
+configure any new adapter.
+
+### Best Practices
+
+- **Choose the Right Adapter**: Select an adapter that fits your backend (e.g., `adapter-axios` for REST APIs,
+ `adapter-graphql` for GraphQL, `firebase` for Firebase and `firebase-admin` for Admin version).
+- **Custom Adapters**: If needed, you can create a custom adapter to handle unique data fetching requirements.
+- **Configuration**: Configure the adapter on the `Client` instance.
+
+#### Example (with axios adapter):
+
+```typescript
+import { Client } from "@hyper-fetch/core";
+import { AdapterAxios } from "@hyper-fetch/adapter-axios";
+
+export const client = new Client({
+ baseUrl: "https://api.example.com",
+}).setAdapter(AdapterAxios());
+```
diff --git a/.cursor/rules/react.mdc b/.cursor/rules/react.mdc
new file mode 100644
index 000000000..4bc9b7a5a
--- /dev/null
+++ b/.cursor/rules/react.mdc
@@ -0,0 +1,83 @@
+---
+description:
+globs:
+alwaysApply: false
+---
+---
+description: React best practices and patterns for modern web applications
+globs: **/*.tsx, **/*.jsx, components/**/*
+---
+
+# React Best Practices
+
+## Component Structure
+- Use functional components over class components
+- Keep components small and focused
+- Extract reusable logic into custom hooks
+- Use composition over inheritance
+- Implement proper prop types with TypeScript
+- Split large components into smaller, focused ones
+
+## Hooks
+- Follow the Rules of Hooks
+- Use custom hooks for reusable logic
+- Keep hooks focused and simple
+- Use appropriate dependency arrays in useEffect
+- Implement cleanup in useEffect when needed
+- Avoid nested hooks
+
+## State Management
+- Use useState for local component state
+- Implement useReducer for complex state logic
+- Use Context API for shared state
+- Keep state as close to where it's used as possible
+- Avoid prop drilling through proper state management
+- Use state management libraries only when necessary
+
+## Performance
+- Implement proper memoization (useMemo, useCallback)
+- Use React.memo for expensive components
+- Avoid unnecessary re-renders
+- Implement proper lazy loading
+- Use proper key props in lists
+- Profile and optimize render performance
+
+## Forms
+- Use controlled components for form inputs
+- Implement proper form validation
+- Handle form submission states properly
+- Show appropriate loading and error states
+- Use form libraries for complex forms
+- Implement proper accessibility for forms
+
+## Error Handling
+- Implement Error Boundaries
+- Handle async errors properly
+- Show user-friendly error messages
+- Implement proper fallback UI
+- Log errors appropriately
+- Handle edge cases gracefully
+
+## Testing
+- Write unit tests for components
+- Implement integration tests for complex flows
+- Use React Testing Library
+- Test user interactions
+- Test error scenarios
+- Implement proper mock data
+
+## Accessibility
+- Use semantic HTML elements
+- Implement proper ARIA attributes
+- Ensure keyboard navigation
+- Test with screen readers
+- Handle focus management
+- Provide proper alt text for images
+
+## Code Organization
+- Group related components together
+- Use proper file naming conventions
+- Implement proper directory structure
+- Keep styles close to components
+- Use proper imports/exports
+- Document complex component logic
\ No newline at end of file
diff --git a/.cursor/rules/tailwind.mdc b/.cursor/rules/tailwind.mdc
new file mode 100644
index 000000000..12d4f91e0
--- /dev/null
+++ b/.cursor/rules/tailwind.mdc
@@ -0,0 +1,83 @@
+---
+description:
+globs:
+alwaysApply: false
+---
+---
+description: Tailwind CSS and UI component best practices for modern web applications
+globs: **/*.css, **/*.tsx, **/*.jsx, tailwind.config.js, tailwind.config.ts
+---
+
+# Tailwind CSS Best Practices
+
+## Project Setup
+- Use proper Tailwind configuration
+- Configure theme extension properly
+- Set up proper purge configuration
+- Use proper plugin integration
+- Configure custom spacing and breakpoints
+- Set up proper color palette
+
+## Component Styling
+- Use utility classes over custom CSS
+- Group related utilities with @apply when needed
+- Use proper responsive design utilities
+- Implement dark mode properly
+- Use proper state variants
+- Keep component styles consistent
+
+## Layout
+- Use Flexbox and Grid utilities effectively
+- Implement proper spacing system
+- Use container queries when needed
+- Implement proper responsive breakpoints
+- Use proper padding and margin utilities
+- Implement proper alignment utilities
+
+## Typography
+- Use proper font size utilities
+- Implement proper line height
+- Use proper font weight utilities
+- Configure custom fonts properly
+- Use proper text alignment
+- Implement proper text decoration
+
+## Colors
+- Use semantic color naming
+- Implement proper color contrast
+- Use opacity utilities effectively
+- Configure custom colors properly
+- Use proper gradient utilities
+- Implement proper hover states
+
+## Components
+- Use shadcn/ui components when available
+- Extend components properly
+- Keep component variants consistent
+- Implement proper animations
+- Use proper transition utilities
+- Keep accessibility in mind
+
+## Responsive Design
+- Use mobile-first approach
+- Implement proper breakpoints
+- Use container queries effectively
+- Handle different screen sizes properly
+- Implement proper responsive typography
+- Use proper responsive spacing
+
+## Performance
+- Use proper purge configuration
+- Minimize custom CSS
+- Use proper caching strategies
+- Implement proper code splitting
+- Optimize for production
+- Monitor bundle size
+
+## Best Practices
+- Follow naming conventions
+- Keep styles organized
+- Use proper documentation
+- Implement proper testing
+- Follow accessibility guidelines
+- Use proper version control
\ No newline at end of file
diff --git a/.cursor/rules/typescript.mdc b/.cursor/rules/typescript.mdc
new file mode 100644
index 000000000..9e3bb09e3
--- /dev/null
+++ b/.cursor/rules/typescript.mdc
@@ -0,0 +1,64 @@
+---
+description: TypeScript coding standards and best practices for modern web development
+globs: **/*.ts, **/*.tsx, **/*.d.ts
+---
+
+# TypeScript Best Practices
+
+## Type System
+
+- Prefer interfaces over types for object definitions
+- Use type for unions, intersections, and mapped types
+- Avoid using `any`, prefer `unknown` for unknown types
+- Use strict TypeScript configuration
+- Leverage TypeScript's built-in utility types
+- Use generics for reusable type patterns
+
+## Naming Conventions
+
+- Use PascalCase for type names and interfaces
+- Use camelCase for variables and functions
+- Use UPPER_CASE for constants
+- Use descriptive names with auxiliary verbs (e.g., isLoading, hasError)
+- Prefix interfaces for React props with 'Props' (e.g., ButtonProps)
+
+## Code Organization
+
+- Keep type definitions close to where they're used
+- Export types and interfaces from dedicated type files when shared
+- Use barrel exports (index.ts) for organizing exports
+- Place shared types in a `types` directory
+- Co-locate component props with their components
+
+## Functions
+
+- Use explicit return types for public functions
+- Use arrow functions for callbacks and methods
+- Implement proper error handling with custom error types
+- Use function overloads for complex type scenarios
+- Prefer async/await over Promises
+
+## Best Practices
+
+- Enable strict mode in tsconfig.json
+- Use readonly for immutable properties
+- Leverage discriminated unions for type safety
+- Use type guards for runtime type checking
+- Implement proper null checking
+- Avoid type assertions unless necessary
+
+## Error Handling
+
+- Create custom error types for domain-specific errors
+- Use Result types for operations that can fail
+- Implement proper error boundaries
+- Use try-catch blocks with typed catch clauses
+- Handle Promise rejections properly
+
+## Patterns
+
+- Use the Builder pattern for complex object creation
+- Implement the Repository pattern for data access
+- Use the Factory pattern for object creation
+- Leverage dependency injection
+- Use the Module pattern for encapsulation
diff --git a/.env b/.env
new file mode 100644
index 000000000..16c346873
--- /dev/null
+++ b/.env
@@ -0,0 +1,2 @@
+NX_SKIP_NX_CACHE=true
+ESLINT_USE_FLAT_CONFIG=false
\ No newline at end of file
diff --git a/.eslintignore b/.eslintignore
new file mode 100644
index 000000000..9d6ce1a59
--- /dev/null
+++ b/.eslintignore
@@ -0,0 +1,21 @@
+dist
+coverage
+
+dist/**/*
+**/dist/**/*
+coverage/**/*
+**/coverage/**/*
+
+node_modules
+node_modules/**/*
+**/node_modules/**/*
+jest.config.js
+jest.config.ts
+jest.setup.ts
+**/jest.setup.ts
+babel.config.js
+rollup.config.js
+tsconfig.json
+coverage
+temp
+release.config.js
\ No newline at end of file
diff --git a/.eslintrc.js b/.eslintrc.js
new file mode 100644
index 000000000..3bc62b591
--- /dev/null
+++ b/.eslintrc.js
@@ -0,0 +1,150 @@
+module.exports = {
+ root: true,
+ parser: "@typescript-eslint/parser",
+ parserOptions: {
+ ecmaVersion: 11,
+ ecmaFeatures: {
+ jsx: true,
+ },
+ project: ["./tsconfig.json", "./packages/*/tsconfig.json", "./documentation/tsconfig.json"],
+ tsconfigRootDir: __dirname,
+ },
+ settings: {
+ "import/resolver": {
+ node: {
+ moduleDirectory: ["node_modules", "src/", "__tests__/"],
+ },
+ },
+ react: {
+ pragma: "React",
+ version: "detect",
+ },
+ },
+
+ overrides: [
+ {
+ files: ["*.ts", "*.tsx", "*.js", "*.jsx"],
+ plugins: ["react", "react-hooks", "eslint-plugin-prettier"],
+ extends: [
+ "eslint:recommended",
+ "plugin:react-hooks/recommended",
+ "prettier",
+ "plugin:react/recommended",
+ "plugin:@typescript-eslint/recommended",
+ "plugin:import/typescript",
+ "airbnb",
+ "airbnb-typescript",
+ "plugin:prettier/recommended",
+ ],
+ rules: {
+ "react-hooks/rules-of-hooks": "error",
+ "react-hooks/exhaustive-deps": "warn",
+ "react/prop-types": "off",
+ "react/jsx-uses-react": "error",
+ "react/jsx-uses-vars": "error",
+ "no-console": ["error", { allow: ["warn", "error"] }],
+ "react/react-in-jsx-scope": "off",
+ "no-continue": "off",
+ "react/display-name": 0,
+ "import/no-extraneous-dependencies": 0,
+ "import/prefer-default-export": 0,
+ "import/no-cycle": 0,
+ "import/no-default-export": ["error"],
+ "max-lines": ["error", 800],
+ "@typescript-eslint/no-explicit-any": "off",
+ "@typescript-eslint/lines-between-class-members": "off",
+ "prettier/prettier": ["error"],
+ "consistent-return": 0,
+ "@typescript-eslint/no-throw-literal": 0,
+ "no-underscore-dangle": 0,
+ "react/jsx-props-no-spreading": 0,
+ "react/function-component-definition": 0,
+ "react/require-default-props": 0,
+ "spaced-comment": 0,
+ "@typescript-eslint/ban-types": [
+ "error",
+ {
+ extendDefaults: true,
+ types: {
+ "{}": false,
+ },
+ },
+ ],
+ "testing-library/render-result-naming-convention": "off",
+ "max-params": ["error", 3],
+ "no-param-reassign": [
+ "error",
+ {
+ props: true,
+ ignorePropertyModificationsFor: ["draft", "acc"],
+ },
+ ],
+ "import/order": [
+ "error",
+ {
+ groups: [
+ ["builtin", "external"],
+ ["internal", "parent", "sibling", "index"],
+ ],
+ pathGroups: [
+ { pattern: "assets/**", group: "sibling", position: "after" },
+ {
+ pattern: "*.style{s,x}",
+ group: "sibling",
+ patternOptions: { matchBase: true },
+ position: "after",
+ },
+ ],
+ warnOnUnassignedImports: true,
+ pathGroupsExcludedImportTypes: ["css"],
+ "newlines-between": "always",
+ },
+ ],
+ },
+ },
+ {
+ files: ["*.spec.ts", "*.spec.tsx", "*.spec.js", "*.spec.jsx"],
+ env: {
+ jest: true,
+ },
+ rules: {
+ "max-lines": "off",
+ },
+ },
+ {
+ files: ["*.mdx"],
+ rules: {
+ "react/jsx-filename-extension": "off",
+ "react/jsx-no-undef": "off",
+ },
+ },
+ {
+ files: ["*.md", "*.mdx"],
+ extends: "plugin:mdx/recommended",
+ globals: {
+ Head: "readonly",
+ details: "readonly",
+ Details: "readonly",
+ code: "readonly",
+ a: "readonly",
+ pre: "readonly",
+ ul: "readonly",
+ li: "readonly",
+ img: "readonly",
+ h1: "readonly",
+ h2: "readonly",
+ h3: "readonly",
+ h4: "readonly",
+ h5: "readonly",
+ h6: "readonly",
+ admonition: "readonly",
+ mermaid: "readonly",
+ TabItem: "readonly",
+ Tabs: "readonly",
+ // Custom components
+ LinkCard: "readonly",
+ ShowMore: "readonly",
+ },
+ },
+ ],
+};
diff --git a/.eslintrc.json b/.eslintrc.json
deleted file mode 100644
index 2d4fff7d8..000000000
--- a/.eslintrc.json
+++ /dev/null
@@ -1,101 +0,0 @@
-{
- "root": true,
- "parser": "@typescript-eslint/parser",
- "parserOptions": {
- "ecmaVersion": 11,
- "ecmaFeatures": {
- "jsx": true
- },
- "project": "./tsconfig.json"
- },
- "settings": {
- "import/resolver": {
- "node": {
- "moduleDirectory": ["node_modules", "src/"]
- }
- },
- "react": {
- "pragma": "React",
- "version": "detect"
- }
- },
- "plugins": ["react", "react-hooks"],
- "extends": [
- "eslint:recommended",
- "plugin:react-hooks/recommended",
- "prettier",
- "plugin:react/recommended",
- "plugin:@typescript-eslint/recommended",
- "plugin:import/typescript",
- "airbnb",
- "airbnb-typescript",
- "plugin:prettier/recommended"
- ],
- "ignorePatterns": [
- "dist",
- "node_modules",
- "jest.config.ts",
- "babel.config.js",
- "rollup.config.js",
- "jest.config.js",
- "tsconfig.json",
- "coverage",
- "temp",
- "release.config.js"
- ],
- "rules": {
- "react-hooks/rules-of-hooks": "error",
- "react-hooks/exhaustive-deps": "warn",
- "react/prop-types": "off",
- "react/jsx-uses-react": "error",
- "react/jsx-uses-vars": "error",
- "no-console": ["error", { "allow": ["warn", "error"] }],
- "react/react-in-jsx-scope": "off",
- "react/display-name": 0,
- "import/no-extraneous-dependencies": 0,
- "import/prefer-default-export": 0,
- "import/no-cycle": 0,
- "@typescript-eslint/no-explicit-any": 0,
- "@typescript-eslint/lines-between-class-members": "off",
- "prettier/prettier": ["error"],
- "consistent-return": 0,
- "@typescript-eslint/no-throw-literal": 0,
- "no-underscore-dangle": 0,
- "react/function-component-definition": 0,
- "testing-library/render-result-naming-convention": "off",
- "import/order": [
- "error",
- {
- "groups": [
- ["builtin", "external"],
- ["internal", "parent", "sibling", "index"]
- ],
- "pathGroups": [
- { "pattern": "assets/**", "group": "sibling", "position": "after" },
- {
- "pattern": "@external/**/*.{css,scss}",
- "group": "sibling",
- "position": "after"
- },
- {
- "pattern": "*.{css,scss}",
- "group": "index",
- "patternOptions": { "matchBase": true },
- "position": "after"
- }
- ],
- "warnOnUnassignedImports": true,
- "pathGroupsExcludedImportTypes": ["css"],
- "newlines-between": "always"
- }
- ]
- },
- "overrides": [
- {
- "files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
- "rules": {
- "testing-library/render-result-naming-convention": "off"
- }
- }
- ]
-}
diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
index 8281db0e4..f42b51aad 100644
--- a/.github/workflows/docs.yml
+++ b/.github/workflows/docs.yml
@@ -15,7 +15,7 @@ jobs:
- name: Set up Node
uses: actions/setup-node@v3
with:
- node-version: "16"
+ node-version: "20.9.0"
cache: "yarn"
- name: Configure AWS Credentials
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index c6482e8fe..9504597ee 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -22,7 +22,7 @@ jobs:
- name: Set up Node
uses: actions/setup-node@v3
with:
- node-version: "16"
+ node-version: "20.9.0"
cache: "yarn"
- name: Install packages
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 2ea98977a..89e536fe6 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -13,7 +13,7 @@ jobs:
- name: Set up Node.js
uses: actions/setup-node@v3
with:
- node-version: "16"
+ node-version: "20.9.0"
cache: "yarn"
- name: Install packages
@@ -28,9 +28,6 @@ jobs:
- name: Typecheck
run: yarn typecheck
- - name: Clear Jest
- run: yarn jest --clearCache
-
- name: Test
run: yarn test --coverage
diff --git a/.gitignore b/.gitignore
index 14700d1e7..cd838c1f1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,9 +5,15 @@ build
dist
tmp
out-tsc
+.next
+.webpack
+.rspack
+.vite
+.react-router/
# dependencies
node_modules
+package-lock.json
# IDEs and editors
/.idea
@@ -49,12 +55,15 @@ Thumbs.db
# testing
coverage
-# Next.js
-.next
+# NX
.nx
+src/mockServiceWorker.js
# Firebase
database-debug.log
firebase-debug.log
firestore-debug.log
-ui-debug.log
\ No newline at end of file
+ui-debug.log
+
+
+storybook-static
\ No newline at end of file
diff --git a/.husky/pre-commit b/.husky/pre-commit
index d0431c355..a8dd5b0dc 100755
--- a/.husky/pre-commit
+++ b/.husky/pre-commit
@@ -2,7 +2,6 @@
. "$(dirname "$0")/_/husky.sh"
yarn commitlint --edit "$1"
-yarn nx run-many --target=build --all --exclude=next,reactjs
-yarn nx run-many --target=lint --all --exclude=next,reactjs --parallel=10
-yarn nx run-many --target=typecheck --all --parallel=10
-yarn nx run-many --target=tests --all --exclude=adapter-firebase,adapter-firebase-admin
+yarn build
+yarn lint
+yarn typecheck
diff --git a/.nvmrc b/.nvmrc
new file mode 100644
index 000000000..c369ba60f
--- /dev/null
+++ b/.nvmrc
@@ -0,0 +1 @@
+20.12.0
\ No newline at end of file
diff --git a/.prettierignore b/.prettierignore
index 93a37955b..c035a6969 100644
--- a/.prettierignore
+++ b/.prettierignore
@@ -1,4 +1,6 @@
# Add files here to ignore them from prettier formatting
/dist
-/coverage
\ No newline at end of file
+/coverage
+/.nx/cache
+/.nx/workspace-data
\ No newline at end of file
diff --git a/README.md b/README.md
index ca8d362e4..5af1fdac4 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@
Framework for fetching and realtime data exchange.
**[Documentation](https://hyperfetch.bettertyped.com/) |
-[Quick Start](https://hyperfetch.bettertyped.com/docs/documentation/getting-started/quick-start) |
+[Quick Start](https://hyperfetch.bettertyped.com/docs/getting-started/quick-start) |
[Guides](https://hyperfetch.bettertyped.com/docs/guides/Basic/Setup)**
@@ -72,11 +72,11 @@ all while facilitating **real-time data exchange**.
🚀 **Queueing** - [Read more](https://hyperfetch.bettertyped.com/docs/guides/advanced/queueing)
-💎 **Response Caching** - [Read more](https://hyperfetch.bettertyped.com/docs/documentation/core/cache)
+💎 **Response Caching** - [Read more](https://hyperfetch.bettertyped.com/docs/core/cache)
🔋 **Offline First** - [Read more](https://hyperfetch.bettertyped.com/docs/guides/advanced/offline)
-📡 **Built-in fetcher** - [Read more](https://hyperfetch.bettertyped.com/docs/documentation/core/adapter)
+📡 **Built-in fetcher** - [Read more](https://hyperfetch.bettertyped.com/docs/core/adapter)
🎟 **Authentication** - [Read more](https://hyperfetch.bettertyped.com/docs/guides/basic/authentication)
@@ -90,7 +90,7 @@ all while facilitating **real-time data exchange**.
The easiest way to get the latest version of Hyper Fetch is to install it via yarn or npm.
-#### [Core](https://hyperfetch.bettertyped.com/docs/documentation/core/overview)
+#### [Core](https://hyperfetch.bettertyped.com/docs/core/overview)
```bash
npm install --save @hyper-fetch/core
@@ -98,7 +98,7 @@ or
yarn add @hyper-fetch/core
```
-#### [Sockets](https://hyperfetch.bettertyped.com/docs/documentation/sockets/overview)
+#### [Sockets](https://hyperfetch.bettertyped.com/docs/sockets/overview)
```bash
npm install --save @hyper-fetch/sockets
@@ -106,7 +106,7 @@ or
yarn add @hyper-fetch/sockets
```
-#### [React](https://hyperfetch.bettertyped.com/docs/documentation/react/overview)
+#### [React](https://hyperfetch.bettertyped.com/docs/react/overview)
```bash
npm install --save @hyper-fetch/core @hyper-fetch/react
diff --git a/babel.config.json b/babel.config.json
deleted file mode 100644
index 065aee77d..000000000
--- a/babel.config.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "babelrcRoots": ["*"]
-}
diff --git a/documentation/.gitignore b/documentation/.gitignore
index acdd81954..5687d1595 100644
--- a/documentation/.gitignore
+++ b/documentation/.gitignore
@@ -3,13 +3,14 @@
# Production
/build
+/docs/api/*
+!/docs/api/getting-started/
+
+
# Generated files
.docusaurus
.cache-loader
-.docgen
-docs/api/*
-
# Misc
.DS_Store
@@ -21,3 +22,4 @@ docs/api/*
npm-debug.log*
yarn-debug.log*
yarn-error.log*
+
diff --git a/documentation/README.md b/documentation/README.md
index 71ad27c48..054638899 100644
--- a/documentation/README.md
+++ b/documentation/README.md
@@ -14,7 +14,7 @@ $ yarn
$ yarn start
```
-This request starts a local development server and opens up a browser window. Most changes are reflected live without
+This command starts a local development server and opens up a browser window. Most changes are reflected live without
having to restart the server.
### Build
@@ -23,14 +23,22 @@ having to restart the server.
$ yarn build
```
-This request generates static content into the `build` directory and can be served using any static contents hosting
+This command generates static content into the `build` directory and can be served using any static contents hosting
service.
### Deployment
+Using SSH:
+
+```
+$ USE_SSH=true yarn deploy
+```
+
+Not using SSH:
+
```
-$ GIT_USER= USE_SSH=true yarn deploy
+$ GIT_USER= yarn deploy
```
-If you are using GitHub pages for hosting, this request is a convenient way to build the website and push to the
+If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the
`gh-pages` branch.
diff --git a/documentation/babel.config.js b/documentation/babel.config.js
deleted file mode 100644
index bfd75dbdf..000000000
--- a/documentation/babel.config.js
+++ /dev/null
@@ -1,3 +0,0 @@
-module.exports = {
- presets: [require.resolve("@docusaurus/core/lib/babel/preset")],
-};
diff --git a/documentation/blog/releases/3.0/2022-12-29-hyper-fetch-3-0.md b/documentation/blog/releases/3.0/2022-12-29-hyper-fetch-3-0.md
index e3f56cf46..72420f2af 100644
--- a/documentation/blog/releases/3.0/2022-12-29-hyper-fetch-3-0.md
+++ b/documentation/blog/releases/3.0/2022-12-29-hyper-fetch-3-0.md
@@ -84,7 +84,7 @@ requests. When we need to listen to events or emit them dynamically, the Hyper F
created a separate dedicated package that, thanks to our partly opinionated architecture, should efficiently enable to
easily handle these events. It's an early version of this package, but we're excited about continuing to work on it!
-[**Read More**](/docs/documentation/sockets/overview)
+[**Read More**](/docs/sockets/overview)
### Events Architecture ✨
@@ -95,7 +95,7 @@ full lifecycle observation of our requests and incredible control over them** -
`we do not have to use Providers in the React` implementation and wrap our application in them, quickly, cleanly and
efficiently, while maintaining full isolation!
-[**Read More**](/docs/documentation/core/overview#full-flow)
+[**Read More**](/docs/core/overview#full-flow)
---
diff --git a/documentation/docs/api/getting-started/index.mdx b/documentation/docs/api/getting-started/index.mdx
new file mode 100644
index 000000000..65f1b7959
--- /dev/null
+++ b/documentation/docs/api/getting-started/index.mdx
@@ -0,0 +1,32 @@
+# Overview
+
+Welcome to the API documentation for the Hyper Fetch framework.
+
+:::note Always Up-to-date
+
+This documentation is continuously updated to reflect the latest changes in the framework, ensuring you always have
+access to the most accurate information.
+
+:::
+
+---
+
+## What You'll Find Here
+
+#### Comprehensive API Reference:
+
+- All interfaces, types, and methods exposed by Hyper Fetch.
+- Usage examples and type structures.
+
+#### Accurate & Up-to-date:
+
+- Documentation is automatically generated using the `@docsgen` library by BetterTyped.
+- Type definitions are sourced directly from the codebase.
+
+---
+
+## How to Use This Section
+
+- Browse the available interfaces and types to understand the API surface.
+- Reference type contracts for seamless integration into your projects.
+- Use the provided examples to speed up development and ensure type safety.
diff --git a/documentation/docs/documentation/02-core/_category_.json b/documentation/docs/core/_category_.json
similarity index 100%
rename from documentation/docs/documentation/02-core/_category_.json
rename to documentation/docs/core/_category_.json
diff --git a/documentation/docs/core/adapter.mdx b/documentation/docs/core/adapter.mdx
new file mode 100644
index 000000000..a53545576
--- /dev/null
+++ b/documentation/docs/core/adapter.mdx
@@ -0,0 +1,253 @@
+---
+sidebar_position: 5
+title: Adapter
+sidebar_label: Adapter
+---
+
+[Read the API Reference »](/docs/api/core/Classes/Adapter.mdx)
+
+The `Adapter` class is the backbone of Hyper Fetch's communication system. It abstracts the details of how requests are
+executed, allowing you to swap between HTTP, GraphQL, Firebase, or any custom transport layer with ease. Adapters are
+responsible for executing requests, mapping payloads and headers, handling query parameters, and integrating with the
+request lifecycle—including progress tracking, cancellation, and error handling.
+
+---
+
+:::tip Purpose
+
+1. **Handles the network communication** for all requests.
+2. Provides **hooks for mapping** headers, payloads, endpoints, and **query parameters**.
+3. Allows you to switch between HTTP, GraphQL, Firebase, and more by swapping adapters.
+4. Enables progress tracking, cancellation and error handling.
+5. **Allows** you to **override default behaviors** for advanced scenarios.
+
+:::
+
+---
+
+## Initialization
+
+By default, Hyper Fetch provides an HTTP adapter for both browser and Node environments. You can also create your own
+adapters to support other protocols or advanced use cases.
+
+```ts title="GraphQL Adapter"
+import { createClient } from "@hyper-fetch/core";
+// highlight-start
+import { GraphqlAdapter } from "@hyper-fetch/graphql";
+// highlight-end
+
+const client = createClient({
+ url: "https://api.example.com",
+ // Change the adapter to GraphQL
+ // highlight-start
+ adapter: GraphqlAdapter(),
+ // highlight-end
+});
+```
+
+---
+
+## Quick Start
+
+You can customize the adapter's behavior by using its configuration methods. For example, to set a custom header mapper:
+
+```ts
+client.adapter.setHeaderMapper((headers, config) => {
+ // Add custom logic for headers
+ return { ...headers, "X-Custom-Header": "value" };
+});
+```
+
+Or to change how payloads are processed:
+
+```ts
+client.adapter.setPayloadMapper((payload, config) => {
+ // Transform payload before sending
+ return JSON.stringify(payload);
+});
+```
+
+---
+
+## Available Methods
+
+
+
+(@import core Adapter type=methods&display=table)
+
+
+
+
+
+---
+
+## Features
+
+1. ### Header Mapper
+
+The header mapper determines how headers are set for each request. By default, it handles FormData and JSON content
+types automatically. You can override this logic for advanced scenarios.
+
+```ts
+client.adapter.setHeaderMapper((headers, config) => {
+ if (config.isAuth) {
+ return { ...headers, Authorization: `Bearer ${config.token}` };
+ }
+ return headers;
+});
+```
+
+---
+
+2. ### Payload Mapper
+
+The payload mapper transforms the request body before it is sent. By default, it handles FormData and JSON. You can
+provide your own logic for custom serialization or encryption.
+
+```ts
+client.adapter.setPayloadMapper((payload, config) => {
+ // Encrypt or transform payload
+ return encryptPayload(payload);
+});
+```
+
+---
+
+3. ### Query Params Mapper
+
+The query params mapper encodes query parameters for the request URL. You can customize the encoding or provide your own
+function.
+
+```ts
+client.adapter.setQueryParamsMapper((params, config) => {
+ // Custom query string encoding
+ return customStringify(params);
+});
+```
+
+You can also set configuration for the query params mapper:
+
+```ts
+client.adapter.setQueryParamsMapperConfig({ arrayFormat: "bracket" });
+```
+
+---
+
+4. ### Endpoint Mapper
+
+The endpoint mapper allows you to transform or format the endpoint before the request is sent. Useful for multi-tenant
+APIs or dynamic routing.
+
+```ts
+client.adapter.setEndpointMapper((endpoint, config) => {
+ return `/v2${endpoint}`;
+});
+```
+
+---
+
+5. ### Defaults
+
+Set **adapter default options** for all requests sent through this adapter:
+
+```ts
+// HTTP adapter options
+client.adapter.setAdapterDefaults((request) => ({
+ timeout: 5000,
+ withCredentials: true,
+}));
+```
+
+:::warning
+
+Each adapter has its own options. Check the API reference for the available options.
+
+:::
+
+---
+
+Set global defaults for **request configuration** (method, auth, deduplication, etc.).
+
+```ts
+client.adapter.setRequestDefaults((options) => ({ ...options, deduplicate: true }));
+```
+
+---
+
+6. ### HyperFetch internal error mapping
+
+Customize how Hyper Fetch internal errors are mapped and handled:
+
+```ts
+client.adapter.setInternalErrorMapping((error) => {
+ // Map or transform error
+ return { ...error, internal: true };
+});
+```
+
+---
+
+:::info Devtools Endpoint Getter
+
+Customize how endpoints of your adapter are displayed in devtools. It allows for nice formatting of the endpoint.
+
+```ts
+client.adapter.setDevtoolsEndpointGetter((endpoint) => endpoint.toUpperCase());
+```
+
+:::
+
+---
+
+## TypeScript Generics
+
+When you create custom adapter, you need to specify the types for the requests templates. Each adapter may have
+different statuses, endpoints, params, additional data returned or required. With generic types you can handle specific
+cases to ensure absolute type-safety and flexibility across different protocols and use cases.
+
+```ts
+class Adapter<
+ AdapterOptions,
+ MethodType extends string,
+ StatusType extends number | string,
+ Extra extends Record,
+ QueryParams = unknown,
+ // ...other generics
+> {
+ /* ... */
+}
+```
+
+Each option describe the type template for requests to be created within client using your adapter.
+
+Refer to the API reference for detailed type parameters and usage examples.
+
+
+
+---
+
+## Related Guides & API Docs
+
+
+
+
diff --git a/documentation/docs/core/cache.mdx b/documentation/docs/core/cache.mdx
new file mode 100644
index 000000000..e8dbefb67
--- /dev/null
+++ b/documentation/docs/core/cache.mdx
@@ -0,0 +1,396 @@
+---
+sidebar_position: 6
+title: Cache
+sidebar_label: Cache
+---
+
+[Read the API Reference »](/docs/api/core/Classes/Cache.mdx)
+
+The `Cache` class is a core subsystem in Hyper Fetch, responsible for storing and managing response data from requests.
+It provides a flexible, event-driven system for data retention, validation, and propagation throughout your application.
+By default, it uses an in-memory `Map` for storage, but you can easily swap in persistent storage solutions like
+`localStorage` or `IndexedDB`.
+
+---
+
+:::tip Purpose
+
+1. **Store and manage request results** for fast, reliable data access.
+2. **Emit events** to keep your app in sync with cache changes.
+3. **Support flexible storage**—from in-memory to persistent solutions.
+4. **Integrate seamlessly** with the Client and Request systems for a unified data flow.
+
+:::
+
+---
+
+## Quick Start
+
+Here's how to get started with the Cache in Hyper Fetch:
+
+```tsx title="Basic Cache Usage"
+import { createClient, Cache } from "@hyper-fetch/core";
+
+// Initialize the client with default cache
+const client = createClient({ url: "http://localhost:3000" });
+
+// Read from cache
+const data = client.cache.get("key");
+
+// Write to cache
+client.cache.set("key", { data: "value" });
+```
+
+You can also customize the cache storage:
+
+```tsx title="Custom Cache Storage"
+const client = createClient({
+ url: "http://localhost:3000",
+ cache: (instance) => new Cache(instance, { storage: localStorage }),
+});
+```
+
+
+
+
+
+---
+
+## Available methods
+
+
+
+(@import core Cache type=methods&display=table)
+
+
+
+
+
+---
+
+## Features
+
+- **Key-based storage**: Data is stored and retrieved using unique cache keys, auto-generated from request details.
+- **Flexible storage**: Use in-memory, localStorage, IndexedDB, or any compatible storage interface.
+- **Event-driven**: Emits events on cache changes for real-time updates.
+- **Persistence**: Easily enable persistent cache across sessions.
+- **Fine-grained control**: Read, write, update, delete, and invalidate cache entries with simple methods.
+- **Integration**: Works seamlessly with the Client and Request systems.
+
+---
+
+## How it works
+
+The cache stores data on a **key-value** basis. The key (usually `cacheKey`) is auto-generated from the request's
+method, endpoint, and query params, but you can override it for advanced scenarios.
+
+```tsx
+const getUsers = client.createRequest()({
+ method: "GET",
+ endpoint: "/users",
+});
+
+// get data by cache key
+// highlight-start
+const data = client.cache.get(getUsers.cacheKey);
+// highlight-end
+
+// or directly by request instance
+// highlight-start
+const data = getUsers.read();
+// highlight-end
+```
+
+You can also set a custom cache key:
+
+```tsx
+const getUsers = client.createRequest()({
+ method: "GET",
+ endpoint: "/users",
+ cacheKey: "CUSTOM_CACHE_KEY",
+});
+
+// get data by custom cache key
+// highlight-start
+const data = client.cache.get("CUSTOM_CACHE_KEY");
+// highlight-end
+
+// or directly by request instance
+// highlight-start
+const data = getUsers.read();
+// highlight-end
+```
+
+---
+
+## CacheKey
+
+The `cacheKey` is a unique identifier for the cache entry. By default it is auto-generated from the request's endpoint,
+url params and query params but you can still add the key manually when setting the Request or generic generator.
+
+```tsx
+const getUser = client.createRequest()({
+ method: "GET",
+ endpoint: "/users/:userId",
+});
+
+// highlight-start
+const cacheKey = getUser.cacheKey; // "/users/:userId"
+const cacheKeyWithParams = getUser.setParams({ userId: 1 }).cacheKey; // "/users/1"
+const cacheKeyWithQueryParams = getUser.setQueryParams({ page: 1 }).cacheKey; // "/users/:userId?page=1"
+// highlight-end
+```
+
+### Custom cacheKey
+
+You can also set a custom cache key:
+
+```tsx
+import { client } from "./api";
+
+const getUser = client.createRequest()({
+ method: "GET",
+ endpoint: "/users/:userId",
+ cacheKey: "CUSTOM_CACHE_KEY",
+});
+
+// highlight-start
+console.log(getUser.cacheKey); // "CUSTOM_CACHE_KEY"
+// highlight-end
+```
+
+### Generic cacheKey
+
+You can also set a generic cache key:
+
+```tsx
+import { client } from "./api";
+
+// highlight-start
+client.setCacheKeyMapper((request) => {
+ if (request.requestOptions.endpoint === "/users/:userId") {
+ return `CUSTOM_CACHE_KEY_${request.params?.userId || "unknown"}`;
+ }
+});
+// highlight-end
+
+const getUser = client.createRequest()({
+ method: "GET",
+ endpoint: "/users/:userId",
+});
+
+// highlight-start
+console.log(getUser.setParams({ userId: 1 }).cacheKey); // "CUSTOM_CACHE_KEY_1"
+// highlight-end
+```
+
+---
+
+## Quick Start
+
+1. ### Reading from Cache
+
+Use the `get` method to read data stored under a given key:
+
+```tsx
+const data = client.cache.get("key");
+```
+
+Or with a request instance:
+
+```tsx
+const getNote = client.createRequest<{ response: Note }>()({
+ method: "GET",
+ endpoint: "/notes/:noteId",
+});
+
+// highlight-start
+const data = getNote.setParams({ noteId: 1 }).read();
+console.log(data); // Note or undefined
+// highlight-end
+```
+
+---
+
+2. ### Writing to Cache
+
+Use the `set` method to store data under a given key. Pass the request instance to ensure correct configuration:
+
+```tsx
+const getNote = client.createRequest()({
+ method: "GET",
+ endpoint: "/notes/:noteId",
+});
+
+client.cache.set(getNote.setParams({ noteId: 1 }), {
+ data: { text: "Hello World" },
+ error: null,
+ status: 200,
+ success: true,
+ extra: xhrExtra,
+});
+```
+
+---
+
+3. ### Updating Cache
+
+Update existing cache entries with the `update` method. The cache will **not** update if the initial data is missing.
+
+:::info Updating rules
+
+Cache will **NOT** update if the initial data is not present in the cache.
+
+:::
+
+```tsx
+client.cache.update(getNote.setParams({ noteId: 1 }), {
+ data: { text: "Hello World" },
+ error: null,
+ status: 200,
+ success: true,
+ extra: xhrExtra,
+});
+
+// Or with a callback
+client.cache.update(getNote.setParams({ noteId: 1 }), (prevData) => ({
+ ...prevData,
+ data: { text: "Hello World" },
+}));
+```
+
+---
+
+4. ### Deleting from Cache
+
+Remove data from the cache using the `delete` method:
+
+```tsx
+client.cache.delete(getNote.setParams({ noteId: 1 }).cacheKey);
+// OR
+client.cache.delete("CUSTOM_CACHE_KEY");
+```
+
+---
+
+5. ### Invalidating Cache
+
+Invalidate cache entries with the `invalidate` method. This sets the `staleTime` to 0, so the next request will refetch
+the data. It also emits an event, triggering refetching in dedicated frameworks integrations like for example in React.
+
+```tsx
+client.cache.invalidate(getNote.setParams({ noteId: 1 }).cacheKey);
+// OR
+client.cache.invalidate("CUSTOM_CACHE_KEY");
+// OR via RegExp
+client.cache.invalidate(new RegExp("CUSTOM_CACHE_KEY"));
+```
+
+---
+
+## Persistence
+
+Enable persistent cache by providing a compatible storage interface (e.g., localStorage, IndexedDB):
+
+```tsx
+const client = createClient({
+ url: "http://localhost:3000",
+ cache: (instance) => new Cache(instance, { storage: localStorage }),
+});
+```
+
+
+
+:::info
+
+Currently, there is no cross-tab synchronization. This is planned for a future release.
+
+:::
+
+---
+
+## Events & Lifecycle
+
+The cache emits events on changes, allowing you to react to updates in real time. See all available events:
+
+
+
+(@import core getCacheEvents type=returns)
+
+
+
+
+
+---
+
+## Configuration Options
+
+You can configure the cache with various options:
+
+(@import core CacheOptionsType type=returns)
+
+
+
+---
+
+## TypeScript
+
+The Cache system is fully typed and integrates with your Client and Request types. When using TypeScript, you get full
+type safety for cache operations, including data, error, and extra fields.
+
+```tsx
+const getUser = client.createRequest<{ response: { name: string } }>()({ endpoint: "/users/:id" });
+
+// highlight-start
+const data = getUser.setParams({ id: 1 }).read();
+console.log(data); // { name: string }
+// highlight-end
+```
+
+---
+
+## See Also
+
+
+
+
diff --git a/documentation/docs/core/client.mdx b/documentation/docs/core/client.mdx
new file mode 100644
index 000000000..fe6a486c2
--- /dev/null
+++ b/documentation/docs/core/client.mdx
@@ -0,0 +1,449 @@
+---
+sidebar_position: 3
+title: Client
+sidebar_label: Client
+---
+
+[Read the API Reference »](/docs/api/core/Classes/Client.mdx)
+
+**`Client`** is the central class for configuring your server connection in Hyper Fetch. It initializes all core
+subsystems—such as queues, cache, and interceptors—and provides a unified way to create and manage requests based on its
+configuration. By keeping all data and logic encapsulated within a single client instance, you ensure that each client
+remains isolated and independent from others.
+
+---
+
+:::tip Purpose
+
+1. **Builder for all of the requests**
+2. Central place for all the default **settings**
+3. Handles **authentication** and **interceptors**
+4. Place where all sub-modules are initialized
+
+:::
+
+---
+
+## Initialization
+
+The client is initialized with the `createClient` function.
+
+```tsx
+import { createClient } from "@hyper-fetch/core";
+
+// highlight-start
+export const client = createClient({ url: "http://localhost:3000" });
+// highlight-end
+```
+
+
+
+---
+
+## Available methods
+
+
+
+(@import core Client type=methods&display=table)
+
+
+
+
+
+---
+
+## Features
+
+Here are some of the most important features available in the Client class.
+
+:::note Builder approach
+
+The `Client` is designed to be used as a builder of requests, serving as the global entry point for server communication
+throughout your application. This approach prevents duplicated logic, promotes a consistent architecture, and makes it
+easier to maintain and test your code by centralizing configuration and types.
+
+:::
+
+1. ### createRequest()
+
+The `createRequest` method is the main method for creating templates for the API connectivity. We use the builder
+pattern to create a request object which contain crucial information about the request - endpoint, method, etc.
+
+Each request keep the reference to the client, so it can access the global settings.
+
+```tsx
+import { createClient } from "@hyper-fetch/core";
+
+const client = createClient({ url: "http://localhost:3000" });
+
+// highlight-next-line
+const getUser = client.createRequest<{ response: User }>()({ endpoint: "/users/1" });
+
+console.log(getUser);
+```
+
+
+
+---
+
+2. ### Authentication
+
+To send authenticated requests, set up the `onAuth` interceptor. Set up the request with the `auth` option set to
+**true**.
+
+```tsx
+import { createClient } from "@hyper-fetch/core";
+import { store } from "./store"; // Your state management store
+
+export const client = createClient({ url: "http://localhost:3000" }).onAuth((request) => {
+ // Get the auth token from your store
+ const state = store.getState();
+ const authToken = state.auth.token;
+
+ // Add the token to the request headers
+ // highlight-start
+ return request.setHeaders({
+ ...request.headers,
+ Authorization: `Bearer ${authToken}`,
+ });
+ // highlight-end
+});
+
+// Create an authenticated request
+export const getUsers = client.createRequest()({
+ endpoint: "/users",
+ // highlight-next-line
+ auth: true, // This enables the onAuth interceptor
+});
+```
+
+
+
+---
+
+3. ### Interceptors
+
+Interceptors are a powerful feature that allows you to modify requests before they're sent or responses before they are
+processed within other core modules.
+
+They can modify the request before it's sent or the response after it's received, depending on the type of interceptor.
+
+#### Request Interceptor
+
+- `onRequest()` - allows to modify the request before it's sent giving ability to modify its data
+- `onAuth()` - allows to modify the request with `auth: true` before it's sent, giving ability to pass custom auth
+ headers or other any options
+
+#### Response Interceptor
+
+There are several methods for intercepting a response from a request:
+
+- `onResponse()` - intercepts any response after it's received to modify it's body
+- `onError()` - intercepts the error response after it's received to modify it's body
+- `onSuccess()` - intercepts the success response after it's received to modify it's body
+
+We can modify received data with these interceptors before it will be emitted to other sub-systems.
+
+```tsx
+import { createClient } from "@hyper-fetch/core";
+
+export const client = createClient({ url: "http://localhost:3000" })
+ // Add request interceptor
+ .onRequest((request) => {
+ // Add custom headers to all requests
+ // highlight-start
+ return request.setHeaders({
+ ...request.headers,
+ "x-custom-header": "custom-value",
+ });
+ // highlight-end
+ })
+ // Add response interceptor
+ .onResponse(async (response, request) => {
+ // Log all responses
+ console.log(`Response for ${request.endpoint}:`, response);
+ // highlight-start
+ return response;
+ // highlight-end
+ })
+ // Add error interceptor
+ .onError(async (errorResponse, request) => {
+ // Handle specific error responses
+ if (errorResponse.status === 401 && !request.used) {
+ // Implement token refresh logic
+ // Set Used allows you to prevent infinite loops of retries
+ // highlight-start
+ return request.setUsed(true).send();
+ // highlight-end
+ }
+ return errorResponse;
+ });
+```
+
+
+
+---
+
+4. ### Global settings
+
+Every module is initialized inside of the `Client` class. This is a perfect place to store and control global settings
+for the adapter, cache, requests or other modules.
+
+```tsx
+import { createClient } from "@hyper-fetch/core";
+
+export const client = createClient({
+ url: "http://localhost:3000",
+});
+
+// highlight-start
+client.adapter.setRequestDefaults({
+ retries: 3, // Retry failed requests 3 times
+ cacheTime: 5 * 60 * 1000, // Cache data for 5 minutes
+ staleTime: 60 * 1000, // Data becomes stale after 1 minute
+
+ // Adapter options
+ options: {
+ timeout: 10000, // 10 seconds timeout for all requests
+ },
+});
+// highlight-end
+
+// These global settings can be overridden for specific requests
+export const getUser = client.createRequest()({
+ endpoint: "/users/:id",
+ method: "GET",
+ // highlight-next-line
+ timeout: 5000, // Override the global timeout of 10000 for this request
+});
+```
+
+
+
+---
+
+5. ### Plugins
+
+Plugins are a powerful feature that allows you to extend the functionality of the client. They can be used to listen to
+the events happening inside of the Hyper Fetch.
+
+```tsx
+import { createClient } from "@hyper-fetch/core";
+import { Plugin } from "@hyper-fetch/core";
+import { DevtoolsPlugin } from "@hyper-fetch/plugin-devtools";
+
+// Add the official devtools plugin
+export const client = createClient({ url: "http://localhost:3000" })
+ .setDebug(true)
+ // highlight-start
+ .addPlugin(
+ DevtoolsPlugin({
+ appName: "My Application",
+ }),
+ );
+// highlight-end
+
+// Create a custom plugin
+const loggingPlugin = new Plugin({
+ name: "logging-plugin",
+})
+ .onRequestStart(({ request }) => {
+ console.log(`Request started: ${request.method} ${request.endpoint}`);
+ })
+ .onRequestSuccess(({ response, request }) => {
+ console.log(`Request succeeded: ${request.method} ${request.endpoint}`, response.data);
+ })
+ .onRequestError(({ response, request }) => {
+ console.error(`Request failed: ${request.method} ${request.endpoint}`, response.error);
+ });
+
+// Add the custom plugin to the client
+// highlight-next-line
+client.addPlugin(loggingPlugin);
+```
+
+---
+
+6. ### Hydration
+
+We can hydrate the client with the data from the server. This is a powerful feature that allows us to pass the data from
+the server to the client for the SSR use cases.
+
+```tsx
+// Server-side code
+import { createClient } from "@hyper-fetch/core";
+
+export const client = createClient({ url: "http://localhost:3000" });
+const userRequest = client.createRequest()({ endpoint: "/users/1" });
+
+// Fetch data on the server
+const response = await userRequest.send();
+
+// Dehydrate the response for client hydration
+// highlight-start
+const dehydratedData = userRequest.dehydrate({ response });
+// highlight-end
+
+// Pass dehydratedData to the client (e.g., as props or through a global state)
+
+// *****************************************************
+// *****************************************************
+// Client-side code
+// *****************************************************
+// *****************************************************
+
+import { createClient } from "@hyper-fetch/core";
+import { useFetch } from "@hyper-fetch/react";
+
+export const client = createClient({ url: "http://localhost:3000" });
+
+// Hydrate the client with server data
+// highlight-start
+client.hydrate([dehydratedData]);
+// highlight-end
+
+// In your React component
+function UserProfile() {
+ // Data will be available immediately from cache, no loading state needed
+ const { data } = useFetch(client.createRequest()({ endpoint: "/users/1" }), {
+ // highlight-next-line
+ revalidate: false, // Prevent automatic refetching
+ });
+
+ return {data?.name}
;
+}
+```
+
+---
+
+## TypeScript
+
+Most important type passed to the `createClient` is the error type. It is a global error type, being used like a default
+for any request errors. It is later combined with the "local error" type of the requests creating the union. This way we
+handle generic errors from the server (global) as well as some validation/business (local) errors for given endpoint.
+
+:::warning Enhancing TypeScript DX
+
+It is important to use the [eslint plugin](/docs/integrations/plugin-eslint/index.mdx) to get the best typescript
+experience. We enhance the abilities of the object generics to provide you with the best possible DX.
+
+:::
+
+```tsx
+import { createClient, AdapterType } from "@hyper-fetch/core";
+
+// highlight-start
+// Define your global error type
+interface ClientErrorType {
+ message: string;
+ code: number;
+}
+
+const client = createClient<{ error: ClientErrorType }>();
+// highlight-end
+```
+
+- `error` defines the global/default error type used in all the requests. It should consist of an `Error` type and your
+ default `ServerErrorType`. It is propagated down to the `createRequest` method, serving as a default for the
+ `globalError` type.
+
+- `adapter` is the generic responsible for shaping options passed to the adapter. Most likely you will change it only
+ when you provide [your custom adapter](/docs/guides/core/02-advanced/custom-adapter.mdx).
+
+## Modules
+
+Client is a place where all the subsystems are initialized. Here is a diagram of the client and its subsystems:
+
+```mermaid
+mindmap
+ root)Client(
+ )Requests(
+ {{Query Params}}
+ {{Payload}}
+ {{Headers}}
+ {{Body}}
+ {{Method}}
+ {{URL}}
+ )Dispatchers(
+ {{Queues}}
+ {{Cancellation}}
+ {{Deduplication}}
+ )Cache(
+ {{Storages}}
+ {{Garbage Collection}}
+ )Adapter(
+ {{HTTP}}
+ {{GraphQL}}
+ {{Firebase}}
+ {{Axios}}
+ )Managers(
+ {{Request Lifecycle}}
+ {{Window Focus}}
+ {{Network Status}}
+ {{Abort Controllers}}
+ {{Logger}}
+ )Plugins(
+ {{Devtools}}
+ {{Observers}}
+```
+
+---
+
+## See Also
+
+
+
+
+
+
+
+
+
+
+
+---
diff --git a/documentation/docs/documentation/02-core/data-flow.mdx b/documentation/docs/core/data-flow.mdx
similarity index 99%
rename from documentation/docs/documentation/02-core/data-flow.mdx
rename to documentation/docs/core/data-flow.mdx
index 947d528cf..573fa1ff3 100644
--- a/documentation/docs/documentation/02-core/data-flow.mdx
+++ b/documentation/docs/core/data-flow.mdx
@@ -1,5 +1,5 @@
---
-sidebar_position: 20
+sidebar_position: 11
title: Core Data Flow
sidebar_label: Data Flow
---
diff --git a/documentation/docs/core/dispatcher.mdx b/documentation/docs/core/dispatcher.mdx
new file mode 100644
index 000000000..d3b754423
--- /dev/null
+++ b/documentation/docs/core/dispatcher.mdx
@@ -0,0 +1,458 @@
+---
+sidebar_position: 7
+title: Dispatcher
+sidebar_label: Dispatcher
+---
+
+[Read the API Reference »](/api/core/Classes/Dispatcher.mdx)
+
+In order to provide advanced features and fetching modes like retries, deduplication, queueing, canceling etc. It can
+catalog the requests providing unique IDs, tracking the lifecycle and triggering the requests at the right time and in
+the right way.
+
+Every request in the dispatcher is stored in the queue structure. This allows us to perform many operations (e.g.
+stopping, pausing, or starting) on the dispatched requests. However, this does not mean that all requests will be sent
+individually; there are multiple dispatching modes available, which you can read about in the
+[dispatching modes](#dispatching-modes) section.
+
+---
+
+:::tip Purpose
+
+1. Orchestrates request flow and lifecycle
+2. Can retry, deduplicate, manage offline mode and more
+3. Allow to pause and resume requests or queue groups
+4. Bridges adapter, cache and managers functionality
+
+:::
+
+---
+
+## How it works
+
+Each request triggered with `send()`, unlike the `exec()` method, goes through the entire lifecycle in the library.
+First, we check the execution mode—whether it is concurrent, queued, cancelable, or deduplicated. This determines how we
+handle the current and previous requests. Next, we add the request to a queue, which is a group of requests with the
+same `queryKey`. Once a request is picked from the queue to be triggered, we assign it a `requestId` and execute it in
+the adapter of our choice. From this point, we trigger the entire lifecycle, including retries, offline handling, and
+request and response events. Finally, we remove the request from the queue (whether successful or not) and pass the data
+to the cache for state handling.
+
+#### Two instances
+
+There are two dispatcher instances in the `Client` class: one for querying and one for mutation requests. This design
+provides greater flexibility for configuration. This way, you can configure data mutation and data querying behavior
+separately. For example, you can set different default settings for each dispatcher.
+
+## QueryKey
+
+The `queryKey` is a unique identifier for the request queues. It is used in propagation and reception of request events
+on a given queue and in management of incoming and outgoing requests. Each detected unique `queryKey` creates isolated
+queue array. By default, keys are auto-generated from the request's endpoint and URL parameters, but you can still add
+the key manually when creating the `Request` or using a generic generator.
+
+```tsx
+const getUser = client.createRequest()({
+ method: "GET",
+ endpoint: "/users/:userId",
+});
+
+// highlight-start
+const queryKey = getUser.queryKey; // "/users/:userId"
+const queryKeyWithParams = getUser.setParams({ userId: 1 }).queryKey; // "/users/1"
+const queryKeyWithQueryParams = getUser.setQueryParams({ page: 1 }).queryKey; // "/users/:userId"
+// highlight-end
+```
+
+### Custom queryKey
+
+You can also set a custom query key:
+
+```tsx
+import { client } from "./api";
+
+const getUser = client.createRequest()({
+ method: "GET",
+ endpoint: "/users/:userId",
+ queryKey: "CUSTOM_QUERY_KEY",
+});
+
+// highlight-start
+console.log(getUser.queryKey); // "CUSTOM_QUERY_KEY"
+// highlight-end
+```
+
+### Generic queryKey
+
+You can also set a generic query key:
+
+```tsx
+import { client } from "./api";
+
+// highlight-start
+client.setQueryKeyMapper((request) => {
+ if (request.requestOptions.endpoint === "/users/:userId") {
+ return `CUSTOM_QUERY_KEY_${request.params?.userId || "unknown"}`;
+ }
+});
+// highlight-end
+
+const getUser = client.createRequest()({
+ method: "GET",
+ endpoint: "/users/:userId",
+});
+
+// highlight-start
+console.log(getUser.setParams({ userId: 1 }).queryKey); // "CUSTOM_QUERY_KEY_1"
+// highlight-end
+```
+
+---
+
+## RequestId
+
+The **`requestId`** is autogenerated by the dispatchers when a request is executed. It is unique within a single
+`Client` instance, but we do not guarantee its uniqueness between different `Client` instances. It's used for precise
+communication with the dispatcher, for example, when listening for particular request events or removing a request.
+
+---
+
+## Available methods
+
+
+
+(@import core Dispatcher type=methods&display=table)
+
+
+
+
+
+---
+
+## Features
+
+Here is a list of features that the dispatcher provides:
+
+1. ### Retrying
+
+One of the features that the dispatcher provides is retrying failed requests. It can retry requests until a successful
+result is obtained or the retry limit is reached.
+
+Below is an example of how to set the request to retry and specify the time between attempts. The response promise will
+be resolved on success or after the last retry attempt.
+
+```tsx
+const getUser = client.createRequest()({
+ method: "GET",
+ endpoint: "/users/:userId",
+ retry: 5,
+ retryTime: 3000,
+});
+
+const response = await getUser.send();
+```
+
+---
+
+2. ### Queues
+
+Dispatchers store requests in queues. Thanks to this, we have more and better control over the request flow. This
+flexibility allows us to `stop()`, `pause()`, and `start()` request execution. We can apply these actions to a single
+request or to entire queues (a new queue is created for each unique `queryKey`).
+
+:::note What is the difference between `stop()` and `pause()`?
+
+The main difference lies in how they handle the currently executing request:
+
+- `stop()` - Cancels the currently executing request, along with all other requests in the queue.
+- `pause()` - Allows the currently executing request to finish, but prevents any further requests from starting.
+
+In both scenarios, the requests are not removed from the queue and can be resumed later.
+
+:::
+
+#### Start
+
+When a queue is stopped, you can use `start()` to resume processing requests.
+
+```tsx live title="Start request queue" size=md
+// Requests will be stopped
+client.fetchDispatcher.stop(getUser.queryKey);
+
+// Trigger the request
+getUser.send();
+
+setTimeout(() => {
+ // Start the request
+ client.fetchDispatcher.start(getUser.queryKey);
+}, 2000);
+```
+
+#### Pause
+
+To pause requests, just use the `pause()` method on the Dispatcher.
+
+```tsx
+// To pause the queue
+// highlight-next-line
+client.fetchDispatcher.pause("queryKey");
+```
+
+:::warning Pausing individual request
+
+You cannot `pause()` individual requests; they can only be stopped.
+
+:::
+
+```tsx live title="Pausing request queue" size=md
+// Trigger the request
+getUser.send();
+
+setTimeout(() => {
+ // Pause the queue, this will complete the in-progress request and hold all others
+ client.fetchDispatcher.pause(getUser.queryKey);
+}, 500);
+
+setTimeout(() => {
+ // Trigger another request, that will be stopped
+ getUser.send();
+}, 1000);
+
+// Start the queue
+setTimeout(() => {
+ client.fetchDispatcher.start(getUser.queryKey);
+}, 4000);
+```
+
+#### Stop
+
+To stop requests use the `stop()` method to stop the queue. It will cancel the in-progress request and hold all others.
+
+```tsx
+// To stop the queue
+// highlight-next-line
+client.fetchDispatcher.stop("queryKey");
+```
+
+```tsx live title="Stopping request queue" size=md
+// Trigger the request
+getUser.send();
+
+setTimeout(() => {
+ // Stop the queue, this will cancel the in-progress request and hold all others
+ client.fetchDispatcher.stop(getUser.queryKey);
+}, 500);
+
+setTimeout(() => {
+ // Trigger another request, that will be stopped
+ getUser.send();
+}, 1000);
+
+// Start the queue, will resume the in-progress request and allow the others to be sent
+setTimeout(() => {
+ client.fetchDispatcher.start(getUser.queryKey);
+}, 4000);
+```
+
+You can also stop an individual request with the `stopRequest()` method. It will cancel the request and remove it from
+the queue.
+
+```tsx
+// To stop individual request
+// highlight-next-line
+client.fetchDispatcher.stopRequest("queryKey", "requestId");
+```
+
+```tsx live title="Stopping individual request" size=md
+let getUserRequestId = "";
+
+// Trigger the request
+getUser.send({
+ onBeforeSent: ({ requestId }) => {
+ getUserRequestId = requestId;
+ },
+});
+
+// Trigger another request
+getUser.send();
+
+// Stop individual request
+setTimeout(() => {
+ client.fetchDispatcher.stopRequest(getUser.queryKey, getUserRequestId);
+}, 1000);
+
+// Start stopped request
+setTimeout(() => {
+ client.fetchDispatcher.startRequest(getUser.queryKey, getUserRequestId);
+}, 3000);
+```
+
+---
+
+3. ### Offline
+
+When the connection is lost, the queue is stopped, and any failed or interrupted requests will wait for the connection
+to be restored before being retried. This prevents data loss and allows us to leverage caching abilities.
+
+```tsx live title=Offline handling
+// Simulate the connection loss
+client.appManager.setOnline(false);
+
+// Trigger the request being offline
+getUser.send();
+
+// Return back online and the request will be resumed
+setTimeout(() => {
+ client.appManager.setOnline(true);
+}, 2000);
+```
+
+To **disable offline mode**, you can set the request's `offline` option to `false`.
+
+```ts
+const newRequest = client.createClient()({
+ endpoint: "/request"
+ // highlight-next-line
+ offline: false
+})
+```
+
+---
+
+## Modes
+
+Each dispatcher queue can operate in several modes, which can be selected via request properties.
+
+### Concurrent
+
+In this mode, requests are not limited and can be executed concurrently. This is the default mode for all requests.
+
+This mode is active when the `queued` property on a request is set to `false`, which is the default.
+
+```tsx live
+import { getUser } from "./api";
+
+// First request
+getUser.send();
+
+// Second request
+getUser.send();
+```
+
+:::tip When it could be useful?
+
+This is the default mode for request execution. Use it to send multiple requests simultaneously and receive responses in
+parallel.
+
+:::
+
+---
+
+### Deduplication
+
+Deduplication optimizes data exchange with the server. If we ask the server for the same data twice at the same time
+with different requests, this mode will perform one call and propagate the response to both sources.
+
+Enable this mode by setting the request `deduplication` prop to true.
+
+```tsx live size=md
+import { getUser } from "./api";
+
+const getUserDeduplicated = getUser.setDeduplicate(true);
+
+// First request
+const request1 = getUserDeduplicated.send();
+
+// Second request (Deduplicated - it will never be triggered)
+const request2 = getUserDeduplicated.send();
+
+setTimeout(async () => {
+ // Third request (Deduplicated - it will never be triggered)
+ const request3 = getUserDeduplicated.send();
+
+ // Responses logs
+ const [response1, response2, response3] = await Promise.all([request1, request2, request3]);
+
+ console.log(response1);
+ console.log(response2);
+ console.log(response3);
+}, 500);
+
+// Wait for the requests to be resolved
+```
+
+:::tip When it could be useful?
+
+Imagine different components making the same request. Instead of sending the same request multiple times, you can group
+them into one and listen to its response. This way, you can avoid over-fetching and improve your application's
+performance.
+
+:::
+
+---
+
+### Cancelable
+
+Cancelable mode avoids race conditions when multiple requests are sent, but only the result of the last one is desired.
+This mode is ideal for paginated lists of data, where only a single page needs to be shown, even if the user triggers
+new requests with rapidly changing pagination.
+
+Enable this mode by setting the request `cancelable` prop to true.
+
+```tsx live size=md
+import { getUser } from "./api";
+
+const getUserCancelable = getUser.setCancelable(true);
+
+// First request
+getUserCancelable.send();
+
+setTimeout(() => {
+ // Second request
+ getUserCancelable.send();
+}, 500);
+```
+
+:::tip When it could be useful?
+
+Cancelable mode is very useful for paginated data. You can cancel previous requests (for example, when pages are
+switched dynamically) and send only the current one, thus avoiding over-fetching.
+
+:::
+
+---
+
+### Queued
+
+This mode is ideal for sending requests sequentially. It allows you to combine requests into an ordered queue that will
+be processed one item at a time. In this mode, you can `start`, `stop`, or `pause` the entire queue, request or whole
+processing.
+
+Enable this mode by setting the request `queued` prop to true.
+
+```tsx live size=md
+import { postFile } from "./api";
+
+const postFileQueued = postFile.setQueued(true);
+
+// First request
+postFileQueued.send();
+postFileQueued.send();
+postFileQueued.send();
+```
+
+:::tip When it could be useful?
+
+This mode is ideal for transferring large amounts of data. It mitigates the impact of network issues by processing
+requests sequentially, which prevents multiple requests from failing if the connection is lost. Additionally, it
+improves user experience by enabling parts of an application to become available as each data transfer completes, rather
+than making the user wait for all transfers to finish.
+
+:::
+
+---
diff --git a/documentation/docs/core/managers.mdx b/documentation/docs/core/managers.mdx
new file mode 100644
index 000000000..6c40ff07e
--- /dev/null
+++ b/documentation/docs/core/managers.mdx
@@ -0,0 +1,257 @@
+---
+sidebar_position: 8
+title: Managers
+sidebar_label: Managers
+---
+
+**Managers** are core subsystems in Hyper Fetch that handle essential app-wide concerns—like network status, request
+lifecycle, and logging. They provide powerful, centralized APIs for managing state, events, and behaviors across your
+application, making advanced features like offline support, cancellation, and debugging easy to implement and maintain
+in other environments like React, Node.js, etc.
+
+The library contains several managers, each supporting a specific subsystem or feature. Understanding these managers
+helps you unlock advanced capabilities and build robust, maintainable applications.
+
+---
+
+## AppManager
+
+[Read the API Reference »](/api/core/Classes/AppManager.mdx)
+
+The **AppManager** detects and manages your application's online/offline state, tracks window focus and blur events, and
+allows integration with custom event sources (such as React Native or Electron). It provides unmount callbacks for easy
+cleanup, making it simple to handle app-wide lifecycle events in any environment.
+
+:::tip Purpose
+
+1. Track **online/offline** status of the app
+2. Detect **window focus** and **blur** events
+3. **Allow custom event** sources for different environments
+
+:::
+
+```tsx title="Listening to App Events"
+// highlight-start
+const unmountFocusListener = client.appManager.events.onFocus(() => {
+ console.log("App is focused!");
+});
+const unmountOfflineListener = client.appManager.events.onOffline(() => {
+ console.log("App is offline!");
+});
+// highlight-end
+
+// ... later, to clean up:
+unmountFocusListener();
+unmountOfflineListener();
+```
+
+:::info
+
+Hyper Fetch event listeners always return unmounting callbacks for easier cleanup handling.
+
+:::
+
+#### Customizing Events
+
+If you're using a non-browser environment (like React Native), you can set custom event handlers:
+
+```ts
+client.appManager.setFocusEvents({
+ onFocus: myCustomFocusHandler,
+ onBlur: myCustomBlurHandler,
+});
+```
+
+### Events
+
+
+
+(@import core getAppManagerEvents type=returns)
+
+
+
+---
+
+## RequestManager
+
+[Read the API Reference »](/api/core/Classes/RequestManager.mdx)
+
+The **RequestManager** manages cancellation tokens for requests, emits events throughout the request lifecycle
+(including start, upload, download, response, and abort), and supports aborting requests by requestId or custom
+abortKey. It enables granular progress tracking and advanced cancellation scenarios for robust request handling.
+
+:::tip Purpose
+
+1. Manage cancellation tokens for requests
+2. Emit events for request lifecycle (start, upload, download, response, abort)
+3. Support aborting by requestId or abortKey
+
+:::
+
+```tsx title="Tracking Upload/Download Progress"
+// highlight-start
+const unmountUploadListener = client.requestManager.events.onUploadProgressById(requestId, (progress) => {
+ console.log("Upload progress:", progress);
+});
+const unmountDownloadListener = client.requestManager.events.onDownloadProgressById(requestId, (progress) => {
+ console.log("Download progress:", progress);
+});
+// highlight-end
+
+// ... later, to clean up:
+unmountUploadListener();
+unmountDownloadListener();
+```
+
+:::info
+
+You can abort requests by their `requestId` or by a custom `abortKey` to cancel groups of requests at once.
+
+:::
+
+### AbortKey
+
+Every request added to the dispatcher creates an abort controller, stored in a Map under its abort key (usually the
+`requestId`). This lets you abort single requests or groups of requests easily.
+
+```tsx
+const getUser = client.createRequest()({
+ method: "GET",
+ endpoint: "/users/:userId",
+});
+
+// highlight-start
+const abortKey = getUser.abortKey; // "/users/:userId"
+const abortKeyWithParams = getUser.setParams({ userId: 1 }).abortKey; // "/users/1"
+const abortKeyWithQueryParams = getUser.setQueryParams({ page: 1 }).abortKey; // "/users/:userId"
+// highlight-end
+```
+
+#### Custom abortKey
+
+You can also set a custom abort key:
+
+```tsx
+import { client } from "./api";
+
+const getUser = client.createRequest()({
+ method: "GET",
+ endpoint: "/users/:userId",
+ abortKey: "CUSTOM_ABORT_KEY",
+});
+
+// highlight-start
+console.log(getUser.abortKey); // "CUSTOM_ABORT_KEY"
+// highlight-end
+```
+
+#### Generic abortKey
+
+You can also set a generic abort key:
+
+```tsx
+import { client } from "./api";
+
+// highlight-start
+client.setQueryKeyMapper((request) => {
+ if (request.requestOptions.endpoint === "/users/:userId") {
+ return `CUSTOM_ABORT_KEY_${request.params?.userId || "unknown"}`;
+ }
+});
+// highlight-end
+
+const getUser = client.createRequest()({
+ method: "GET",
+ endpoint: "/users/:userId",
+});
+
+// highlight-start
+console.log(getUser.setParams({ userId: 1 }).queryKey); // "CUSTOM_QUERY_KEY_1"
+// highlight-end
+```
+
+---
+
+### Events
+
+
+
+(@import core getRequestManagerEvents type=returns)
+
+
+
+```ts title=Example
+client.requestManager.events.onResponse((response, details) => {
+ // Handle response
+});
+```
+
+---
+
+## LoggerManager
+
+[Read the API Reference »](/api/core/Classes/LoggerManager.mdx)
+
+The **LoggerManager** centralizes logging for all subsystems, enables creation of custom loggers for different modules
+or features, and ensures consistent logging by inheriting parent configuration. It offers flexible log levels and output
+formatting to keep logs organized and actionable.
+
+:::tip Purpose
+
+1. Centralize logging for all subsystems
+2. Enable creation of custom loggers for modules/features
+3. Inherit parent configuration for consistent logging
+
+:::
+
+```ts title="Custom Logger Example"
+// highlight-start
+const logger = client.loggerManager.init("My Module");
+logger.error("Something went wrong!"); // Output: [My Module] Something went wrong!
+// highlight-end
+```
+
+---
+
+:::info Best Practices
+
+- Always clean up event listeners using the returned unmount callbacks to avoid memory leaks.
+- Use custom abort keys for advanced cancellation scenarios (e.g., aborting all requests for a specific feature).
+- Leverage custom loggers to keep logs organized and actionable.
+
+:::
+
+---
+
+## See Also
+
+
+
+
+
+
diff --git a/documentation/docs/core/mocking.mdx b/documentation/docs/core/mocking.mdx
new file mode 100644
index 000000000..1bbaef099
--- /dev/null
+++ b/documentation/docs/core/mocking.mdx
@@ -0,0 +1,277 @@
+---
+sidebar_position: 10
+title: Mocking
+sidebar_label: Mocking
+---
+
+[Read the API Reference »](/api/core/Classes/Request.mdx#setmock)
+
+Mocking is a built-in feature of [Request](/docs/core/Request). It is a feature that allows for mock the response for a
+given endpoint at the same time keeping the **complete request lifecycle** and events. Thanks to the design of the
+library, we can also micro-manage things like upload/download progresses, timings, trigger all kinds of errors for
+amazing developer experience. It is a great way to test your code in isolation, without relying on external services and
+keeping the **full type safety** of your code.
+
+---
+
+:::tip Purpose
+
+1. Control upload/download progress and timings
+2. Simulate errors and timeouts
+3. Test edge cases and custom scenarios
+4. Keep your tests fast, reliable, and independent
+
+:::
+
+---
+
+## How it works?
+
+To add a mock to a request, we need to use the `setMock(mockFn, config)` method. It accepts a function that returns a
+mock response. With this simple concept you're able to introduce any mocking approach of your choice.
+
+:::warning Reference change
+
+Method `setMock()` is the only method modifying the Request reference.
+
+This will allow us to mock every request in given group.
+
+:::
+
+```tsx live
+const getNotes = client.createRequest()({
+ endpoint: "/notes",
+});
+
+getNotes.setMock(
+ // Our mock function
+ ({ request, requestId }) => {
+ return {
+ data: {
+ items: [{ text: "This is mocked note" }],
+ },
+ };
+ },
+ // Config
+ {
+ responseTime: 500,
+ requestTime: 500,
+ totalUploaded: 1000,
+ totalDownloaded: 1000,
+ },
+);
+
+const response = await getNotes.send();
+console.log(response);
+```
+
+---
+
+## Options
+
+What you return from the mocker is used to generate the output and behavior of the mocker.
+
+### Response
+
+The base API requires you to return the response for the mocked request. This part defines how our data will look like.
+
+(@import core MockResponseType type=returns&display=table)
+
+### Config
+
+There is also additional config which can specify behavioral aspect of the mocker. How long it should be processed,
+should it throw timeout error or how much of a data we want to mock for the transfer updates.
+
+(@import core MockerConfigType type=returns&display=table)
+
+```tsx
+const request = client
+ .createRequest()({ endpoint: "shared-base-endpoint" })
+ .setMock(
+ () => {
+ // Data part
+ return {
+ data: { mocking: "is fun" },
+ status: 200,
+ };
+ },
+ {
+ // Config part
+ requestTime: 40,
+ responseTime: 60,
+ totalUploaded: 1000,
+ totalDownloaded: 1000,
+ },
+ );
+```
+
+In the example above - the request phase will take 40 milliseconds and during this phase 1000 'bytes' will be "uploaded"
+(and `onUploadProgress` events will be emitted). The response phase will take 60 millisecond and during this phase 1000
+'bytes' will be "downloaded" (and `onDownloadProgress` events will be emitted). In fact no data-exchange occurs, but we
+will make sure to simulate it for you.
+
+---
+
+## Usage and use cases
+
+#### Request context
+
+The mocker is now used by passing a callback function to `setMock`. This function receives the request context and
+returns the mock response. This allows for dynamic mocking, dependent on the passed arguments during execution.
+
+```tsx
+const mockedRequest = client
+ .createRequest()({ endpoint: "/users/:id" })
+ .setMock(({ request }) => {
+ const { params } = request;
+ if (params.id === 11) {
+ return { data: [1, 2, 3], config: { status: 222 } };
+ }
+ return { data: [4, 5, 6], status: 200 };
+ });
+```
+
+The passed method may also be asynchronous:
+
+```tsx
+const mockedRequest = client
+ .createRequest<{ response: Record }>()({ endpoint: "users/:id" })
+ .setMock(async (request) => {
+ // Do some asynchronous processing of the payload
+ const myData = await processPayload(request.payload);
+
+ return { data: myData, status: 200 };
+ });
+```
+
+> **Note:** Only the callback function form is supported. Passing objects, arrays, or lists of functions is no longer
+> available.
+
+#### Canceling
+
+Canceling a request works the same way as in the real request. It will throw an error and the request will be canceled.
+
+```tsx live
+const request = client.createRequest()({
+ endpoint: "some-endpoint",
+});
+
+request.setMock(
+ () => {
+ return {
+ data: { mocking: "is fun" },
+ status: 200,
+ };
+ },
+ {
+ requestTime: 1000,
+ responseTime: 1000,
+ },
+);
+
+const response = request.send();
+
+setTimeout(() => {
+ request.abort();
+}, 1000);
+```
+
+#### Timeout
+
+You can simulate timeout error by setting `timeout` to `true` in the config.
+
+```tsx live
+const request = client.createRequest()({
+ endpoint: "shared-base-endpoint",
+});
+
+request.setMock(
+ () => {
+ return {
+ data: { mocking: "is fun" },
+ status: 200,
+ };
+ },
+ {
+ // It will take 2s to be processed
+ requestTime: 2000,
+ responseTime: 2000,
+ totalUploaded: 1000,
+ totalDownloaded: 1000,
+ // Timeout error will be thrown after 1s
+ timeout: 2000,
+ },
+);
+
+const response = await request.send();
+console.log(response);
+```
+
+---
+
+## Mocking state
+
+Apart from adding a mock to a request, you can also remove it or disable it.
+
+### How to remove mocker?
+
+If you need to remove the mocker from a request, use the `clearMock()` method. This way mocker is disabled and mock data
+is removed.
+
+```tsx
+request.clearMock();
+```
+
+### Disabling single mocker
+
+Instead of removing mocker, you can also disable mocker and enable mocker at will with the `request.setMockingEnabled`
+method. This way if you set mocking data, it will be kept and not removed as in the `clearMock` case.
+
+```tsx
+const mockedRequest = request.setMock({ data: fixture }); // mock is set
+... // Here mocker works as usual
+mockedRequest.setMockingEnabled(false); // Mocker is disabled
+... // Request works as usual
+mockedRequest.setMockingEnabled(true); // Mocker is enabled once again
+```
+
+### Disabling mocking for all requests
+
+If you want to disable mocking for all requests of a given `client` instance - you can use the
+`client.setMockingEnabled` method. This way all related requests will behave 'as usual' and setting/enabling mocks on
+single requests will not have any effect.
+
+```tsx
+const client = new Client(...);
+const mockedRequest_1 = newClient.createRequest()({ ... }).setMock({ data: fixture1 });
+const mockedRequest_2 = newClient.createRequest()({ ... }).setMock({ data: fixture2 });
+... // Here mocked requests return mocked data.
+client.setMockingEnabled(false) // All mocks are disabled
+... // Here requests work as usual
+client.setMockingEnabled(true) // All mocks are enabled once again
+```
+
+---
+
+## See also
+
+
+
+
+
+
diff --git a/documentation/docs/core/overview.mdx b/documentation/docs/core/overview.mdx
new file mode 100644
index 000000000..5ac62f5d0
--- /dev/null
+++ b/documentation/docs/core/overview.mdx
@@ -0,0 +1,216 @@
+---
+sidebar_position: 1
+title: Core - Overview
+sidebar_label: Overview
+---
+
+import { LinkCard } from "@site/src/components";
+
+# Overview
+
+> To truly understand the purpose of Hyper Fetch and the reasoning behind its design choices, it's helpful to explore
+> the core principles that shape its development. Gaining insight into these foundations will help you decide if Hyper
+> Fetch aligns with your project's needs.
+
+---
+
+## These are our core principles.
+
+### Consistency for projects
+
+In many projects, fetching data from APIs is handled differently, leading to a lack of consistency across codebases.
+This inconsistency makes it harder for developers to onboard and understand the code, increasing both learning time and
+maintenance costs. Often, teams reinvent fetching logic from scratch for each project, which not only wastes effort but
+also makes it difficult to achieve uniformity even within a single project.
+
+
+
+Furthermore, the absence of type safety in many fetchers can introduce subtle bugs and runtime errors, causing
+significant issues in production environments. By providing a standardized, typesafe approach to data fetching, Hyper
+Fetch ensures consistency and reliability across all your projects.
+
+```ts
+import { client } from "./client";
+
+type RequestParams = {
+ response: { message: string };
+ payload: { name: string };
+ queryParams: { additionalParam: string };
+ error: { code: number; message: string };
+};
+
+const someRequest = client.createRequest({
+ url: "/api/some-request/:id",
+});
+
+// ⛔ Typescript error, you must pass payload, params and query params
+const { data, error } = await someRequest.send();
+
+// ✅ Now it's ok
+const { data, error } = await someRequest.send({
+ data: {
+ name: "John",
+ },
+ params: {
+ id: "123",
+ },
+ queryParams: {
+ additionalParam: "test",
+ },
+});
+```
+
+---
+
+### Classes as a composable building block
+
+A class-based architecture underpins every important module, bringing several advantages to the table. Testing and
+mocking become much simpler, which helps maintain code quality and reliability. When building
+[stories](https://storybook.js.org/docs/get-started/whats-a-story) for components that use fetchers, the encapsulation
+of logic in reusable classes streamlines the process.
+
+Accessing and manipulating data within these classes is also straightforward, making debugging and extending
+functionality easier. This modular approach encourages reusability and maintainability throughout the codebase.
+
+```tsx
+import { client } from "./client";
+
+const getUsers = client.createRequest<{ response: User[]; queryParams?: { search?: string } }>({
+ url: "/api/users/:id",
+ method: "GET",
+});
+
+console.log(getUsers.endpoint); // /api/users/:id
+
+const getUser = getUsers.setParams({ id: "123" });
+
+console.log(getUser.endpoint); // /api/users/123
+console.log(getUser.requestOptions.endpoint); // /api/users/:id
+```
+
+---
+
+### Request as a fetching template
+
+Requests serve as the core templates for making API queries. With full type safety and explicit type definitions, your
+data fetching logic remains robust and predictable. All essential elements of an API call endpoints, parameters,
+payloads, methods, and more are accessible through a single, unified interface. This design streamlines the process of
+writing tests, stories, and mocks, eliminating the need for custom hooks for every request.
+
+Since requests can be executed outside the main application logic, advanced scenarios like server-side rendering (SSR)
+become possible, allowing fetching logic to be shared between server and client.
+
+```ts
+import { useFetch } from "@hyper-fetch/react";
+import { client } from "./client";
+
+// Create a request which is a template for the request
+const getUsers = client.createRequest<{ response: User[]; queryParams?: { search?: string } }>({
+ url: "/api/users",
+ method: "GET",
+});
+
+// Then modify it as you need
+const getUsersWithSearch = getUsers.setQueryParams({ search: "John" });
+
+// Use on server
+const loader = async () => {
+ const { data, error } = await getUsersWithSearch.send();
+
+ return { data, error };
+};
+
+// Use on client
+const Component = () => {
+ const { data, error } = useFetch(getUsersWithSearch);
+
+ return {data?.response.map((user) => user.name)}
;
+};
+```
+
+This flexibility empowers you to manage loading states and data flow more effectively across your application.
+
+---
+
+### Access to whole request lifecycle
+
+Unlike many popular data fetching libraries, such as React Query or SWR, which are decoupled from the underlying
+fetchers like Axios or the native Fetch API, Hyper Fetch provides comprehensive access to the entire request lifecycle.
+
+Important information such as progress updates, abort signals, or authentication handling does not need to be
+implemented manually for each project. This unified approach makes it easy to track when a request starts uploading,
+when a response begins, or when the process completes.
+
+```mermaid
+ timeline
+ title Request Lifecycle
+ 1. Pre-Request : Deduplication : Queueing : Interceptors
+ 2. Request : onRequestStart() : onUploadProgress() : onRequestEnd()
+ 3. Side Effects : onAbort() : onRemoved() : Stop() : Start()
+ 4. Response : onResponseStart() : onDownloadProgress() : onResponseEnd()
+ 5. Result : Interceptors : onSuccess() : onError() : onFinish()
+```
+
+As a result, powerful features like integrated devtools, detailed analytics, and enhanced logging are readily available,
+contributing to a better developer experience and more maintainable applications.
+
+:::note Unified lifecycle layer
+
+Above timeline works for all integrations, including HTTP, GraphQL, Firebase, and more.
+
+It gives unified layer for tracking it and managing exactly as you want.
+
+:::
+
+---
+
+### Standardized API for all integrations
+
+A unified API for interacting with server data is offered, regardless of the underlying technology be it HTTP, GraphQL,
+Firebase, or any other integration. Every request is composed from the same set of building blocks, with consistent
+properties such as endpoint, method, parameters, payload, and query parameters.
+
+This standardization simplifies the learning curve for developers and makes it easier to switch between different
+integrations without having to relearn new APIs. Maintaining and extending your codebase becomes more straightforward,
+as you only need to implement a simple adapter interface to add new integrations.
+
+This approach keeps your code clean, easy to understand, and highly maintainable, while also enabling rapid adoption of
+new technologies as they emerge.
+
+---
+
+### Event-driven architecture
+
+An event-driven architecture facilitates communication between modules, making it exceptionally easy to extend the
+library with new features, such as custom devtools or advanced analytics.
+
+This approach also integrates seamlessly with other tools, like the React hooks provided by Hyper Fetch, enabling you to
+build live and realtime experiences with minimal effort. Modifying the core Client's cache is straightforward, allowing
+you to create dynamic, responsive applications that can adapt to changing data in real time.
+
+This flexibility and extensibility are key strengths, empowering you to build robust, feature-rich applications with
+ease.
+
+```tsx
+import { client } from "./client";
+
+// All events are available on the client sub modules
+console.log(client.cache.events); // all emitters and listeners
+console.log(client.fetchDispatcher.events); // all emitters and listeners
+console.log(client.submitDispatcher.events); // all emitters and listeners
+console.log(client.requestManager.events); // all emitters and listeners
+console.log(client.appManager.events); // all emitters and listeners
+// etc...
+```
+
+:::info Event-driven architecture
+
+With this simple approach, we can redirect all events to other systems, such as devtools. At the same time, it serves
+the internal logic of Hyper Fetch well and plays a significant role in its React implementation.
+
+:::
diff --git a/documentation/docs/core/plugin.mdx b/documentation/docs/core/plugin.mdx
new file mode 100644
index 000000000..2bfb18b07
--- /dev/null
+++ b/documentation/docs/core/plugin.mdx
@@ -0,0 +1,192 @@
+---
+sidebar_position: 9
+title: Plugin
+sidebar_label: Plugin
+---
+
+[Read the API Reference »](/api/core/Classes/Plugin.mdx)
+
+Plugins allow you to connect into the lifecycle of the whole library. They expose different sets of the methods allowing
+you to react to particular events happening within a system.
+
+---
+
+:::tip Purpose
+
+1. Persists request side-effects
+2. Manipulates the lifecycle and allows hooking in
+
+:::
+
+---
+
+## How to use?
+
+The best way to create new plugin is to wrap the `Plugin` class into a function. This way you can pass in the
+configuration options and return the plugin instance.
+
+```ts title="Creating a new plugin"
+import { Plugin } from "@hyper-fetch/core";
+
+const MyPlugin = ({ module }: { module: string }) => {
+ // highlight-start
+ return new Plugin({
+ // Hook into creation of the request and log it
+ onRequestCreate: (request) => {
+ console.log(`[${module}] Request created`, request);
+ },
+ });
+ // highlight-end
+};
+
+const client = new Client({
+ url: "https://api.example.com",
+ // highlight-start
+}).addPlugin(MyPlugin({ module: "MyApp" }));
+// highlight-end
+```
+
+---
+
+## Available methods
+
+
+
+(@import core Plugin type=methods&display=table)
+
+
+
+
+
+---
+
+## Use cases
+
+### Logging
+
+Plugins are heavily used by our devtools system to provide you with the live feed of what is happening in your
+application. They are great for logging, tracking, debugging and collecting metrics.
+
+### Persistence
+
+There are many applications which require you to persist the state of the application. After reloading of the browser,
+app or server you need to keep up with the unsent requests.
+
+:::note Other solutions
+
+There are many solutions for persistence, all of them approach this problem by introducing the sync mechanisms and local
+DBs. Among them you can find:
+
+- [WatermelonDB](https://github.com/Nozbe/WatermelonDB)
+- [PouchDB](https://pouchdb.com/)
+- [Lowdb](https://github.com/typicode/lowdb)
+
+:::
+
+Hyper Fetch being the fetcher and a server state manager it is able to persist the state of the application. Not only
+that - it can store and persist requests which are not triggered yet - for example if you're in the offline mode.
+
+```ts live title="Persisting requests" console
+import { getUser } from "./api";
+
+// highlight-next-line
+const jsonRequest = getUser.toJSON();
+
+console.log(jsonRequest);
+// use JSON.stringify to get the same result
+console.log(JSON.stringify(getUser, null, 4));
+```
+
+Having the request in the JSON format you can easily persist it in the persistent storage like local storage or any
+other storage you want.
+
+Now imagine our app is offline, we close it and open it again. We can see that the request is still in the persistent
+storage and we can trigger it again.
+
+```ts live title="Triggering requests" size=md console
+import { getUser } from "./api";
+
+const jsonRequest = getUser.toJSON();
+
+// Recreate the request from the JSON
+// highlight-next-line
+const request = Request.fromJSON(client, jsonRequest);
+
+request.setMock(() => ({
+ data: {
+ name: "John Doe",
+ age: 20,
+ },
+ status: 200,
+}));
+
+// Call the request
+const response = await request.send();
+
+console.log(response);
+```
+
+We don't have to do it for every request. To do so, we can attach into the Dispatcher lifecycle and on the
+`onDispatcherItemAdded` and `onDispatcherItemDeleted` events. With them we can add the stringified requests to the
+persistent storage.
+
+Then on the start of the app we can trigger the requests from the persistent storage - this is because after refresh of
+the app Dispatchers do not have access to the persisted storage with our requests. At this time we can add the requests
+to the Dispatcher and trigger them or wait a bit waiting for the app to load.
+
+```ts live title="Triggering requests" size=md console
+// Create a plugin to persist the requests
+const PersistPlugin = () => {
+ return new Plugin()
+ .onDispatcherItemAdded(({ queueItem }) => {
+ localStorage.setItem(queueItem.requestId, JSON.stringify(queueItem.request.toJSON()));
+ })
+ .onDispatcherItemDeleted(({ queueItem }) => {
+ localStorage.removeItem(queueItem.requestId);
+ })
+ .onMount(() => {
+ // Trigger the requests from the persistent storage or reload
+ const requests = Object.values(localStorage).map((request) => Request.fromJSON(client, JSON.parse(request)));
+ if (requests.length > 0) {
+ requests.forEach((request) => {
+ request.send();
+ });
+ }
+ });
+};
+
+// Add the plugin to the client
+client.addPlugin(PersistPlugin());
+```
+
+That's it! It is very simple concept, so keep that in mind when you're building your app.
+
+:::info
+
+We are waiting for your feedback on this feature. If you have any ideas or suggestions, please let us know. We are very
+determined to make it better and more useful for you.
+
+:::
+
+There are few more aspects that could be worth mentioning like:
+
+1. **Optimistic approach** when you want to reflect all of the changes from your persisting requests inside of your UI.
+
+2. Topic of the **connectivity** itself. Your backend need to track all of the persistent requests with some kind of
+ identifier from the frontend - possibly passed with a Header or a Query Parameter. **To prevent duplicates and
+ conflicts**, you need to have some kind of a logic to prevent them.
+
+These are large topics deserving their own guides, so stay tuned!
+
+---
+
+## Parameters
+
+Configuration options
+
+(@import core PluginOptionsType type=returns)
diff --git a/documentation/docs/core/quick-start.mdx b/documentation/docs/core/quick-start.mdx
new file mode 100644
index 000000000..25c20f9b3
--- /dev/null
+++ b/documentation/docs/core/quick-start.mdx
@@ -0,0 +1,113 @@
+---
+sidebar_position: 2
+title: Quick Start
+sidebar_label: Quick Start
+---
+
+Hyper Fetch's core is framework-agnostic, requiring no external libraries to function.
+
+:::secondary What you'll learn
+
+- How to initialize the client
+- How to create requests
+- How to interact with the server
+
+:::
+
+---
+
+### 1. Initialize the Client
+
+The first step is to initialize the **[Client](/core/client.mdx)**. It manages the basic server connection configuration
+and all of Hyper Fetch's essential elements, such as **dispatchers**, **cache**, and **app managers**. Begin by
+specifying the `url` of your server.
+
+```tsx title="client.ts"
+import { Client } from "@hyper-fetch/core";
+
+export const client = new Client({ url: "http://localhost:3000" });
+```
+
+---
+
+### 2. Create Requests
+
+Once the client is set up, use its `createRequest` method to define **[requests](/core/request.mdx)** and their
+associated types.
+
+:::caution
+
+We are using currying to achieve auto generated types for the endpoint string. This solution will be removed once
+[https://github.com/microsoft/TypeScript/issues/10571](https://github.com/microsoft/TypeScript/issues/10571) get
+resolved.
+
+:::
+
+```tsx title="requests.ts"
+import { client } from "../client.ts";
+
+type ResponseType = { token: string; refreshToken: string };
+type PayloadType = { email: string; password: string };
+
+const login = client.createRequest<{
+ response: ResponseType;
+ payload: PayloadType;
+}>()({
+ method: "POST",
+ endpoint: "/auth/login",
+});
+
+const getUsers = client.createRequest<{
+ response: User[];
+ queryParams?: { page?: number; limit?: number; search?: string };
+}>()({
+ method: "GET",
+ endpoint: "/users",
+});
+```
+
+---
+
+### 3. Interact with server
+
+Once you have your request instances, you can interact with the server. This can be done in two primary ways:
+
+```tsx title="users.ts"
+import { getUsers } from "requests";
+
+const fetchUsers = async () => {
+ const { data, error, status } = await getUsers.send();
+
+ if (data) {
+ // work with User[] data
+ // e.g., console.log(data);
+ } else {
+ // handle error
+ // e.g., console.error(error, status);
+ }
+};
+```
+
+```tsx title="login.ts"
+import { login } from "requests";
+
+const handleLogin = async (values: { email: string; password: string }) => {
+ const { data, error, status } = await login.send({ data: values });
+
+ if (data) {
+ // perform login
+ // e.g., store data.token
+ } else {
+ // handle error
+ // e.g., console.error(error, status);
+ }
+};
+```
+
+---
+
+:::success That's it!
+
+You've seen how straightforward it is to get started with Hyper Fetch.
+
+:::
diff --git a/documentation/docs/core/request.mdx b/documentation/docs/core/request.mdx
new file mode 100644
index 000000000..bd8c701d4
--- /dev/null
+++ b/documentation/docs/core/request.mdx
@@ -0,0 +1,938 @@
+---
+sidebar_position: 4
+title: Request
+sidebar_label: Request
+---
+
+[Read the API Reference »](/docs/api/core/Classes/Request.mdx)
+
+The `Request` class is the cornerstone of Hyper Fetch's data-fetching system. It provides a **powerful, type-safe way to
+define, configure, and manage API requests** throughout your application. By encapsulating all the details needed to
+perform a request—such as endpoint, method, parameters, payload, and behavior - `Request` ensures consistency,
+predictability, and flexibility in how you interact with remote data sources.
+
+With a strict and predictable data structure, `Request` makes it easy to serialize, persist, and rehydrate request
+states, enabling advanced features like offline support, caching, and queueing. Its design, especially when paired with
+TypeScript, helps you catch errors early and build robust, maintainable data flows.
+
+---
+
+:::tip Purpose
+
+1. Requests role is to create **consistent API request templates**.
+2. All requests "templates" are **reusable** and share the data structure.
+3. They behave in the same way no matter what the adapter is, to improve reusability.
+4. Request class **holds instructions** on how requests should be sent, queued, retried, or cancelled.
+5. Responses are **typed** and **structured** to make it easy to work with the data.
+
+:::
+
+---
+
+## Initialization
+
+Request should be initialized from the [Client](/docs/core/client) instance with `createRequest` method. This passes a
+shared reference to the place that manages communication in the application.
+
+```tsx title="Example of Request initialization"
+import { client } from "./client";
+
+const getUser = client.createRequest()({
+ endpoint: "/users/:userId",
+});
+```
+
+```tsx live title="Simple fetch" size="small"
+const response = await getUser.send({ params: { userId: 1 } });
+
+console.log(response);
+```
+
+:::caution TypeScript Currying Note
+
+The `createRequest` method currently employs a currying pattern to facilitate auto-generated TypeScript types for
+endpoint strings. This is a temporary approach until
+[this specific TypeScript issue](https://github.com/microsoft/TypeScript/issues/10571) is resolved, which will allow for
+a more direct typing mechanism.
+
+:::
+
+---
+
+## Quick Start
+
+Here is a quick start guide to help you get started with Requests.
+
+### Fetching
+
+There are two main methods to send a request with Hyper Fetch - `send(options)` and `exec(options)`.
+
+```mermaid
+ timeline
+ title Request Lifecycle
+ 1. Pre-Request : Deduplication : Queueing : Interceptors
+ 2. Request : onRequestStart() : onUploadProgress() : onRequestEnd()
+ 3. Side Effects : onAbort() : onRemoved() : Stop() : Start()
+ 4. Response : onResponseStart() : onDownloadProgress() : onResponseEnd()
+ 5. Result : Interceptors : onSuccess() : onError() : onFinish()
+```
+
+1. #### `.send(options)`
+
+You can perform a request with the `send(options)` method. This is the most common way to send a request with Hyper
+Fetch. It triggers the request's lifecycle, including queueing, deduplication, and response handling, and returns the
+server's response in a developer-friendly format.
+
+```tsx
+// Simple fetch
+const { data, error } = await getNotes.setQueryParams({ sort: "age" }).send();
+
+// Multiple chained methods
+const { data, error } = await getCategory.setParams({ categoryId: 2 }).send();
+
+// Passing options
+const { data, error } = await getCategory.send({ params: { categoryId: 1 }, queryParams: { sort: "createdAt" } });
+```
+
+2. #### `.exec(options)`
+
+This method is very similar to `send` but it ignores the built-in features - like for example deduplication or caching.
+It is useful when you want to execute a request outside of the normal flow or when you want to bypass the cache
+interactions - for example while using in SSR environments.
+
+```tsx
+const { data, error } = await getUser.exec();
+```
+
+
+
+---
+
+### Request Options
+
+Each request can be configured with options. We can specify things like `endpoint`, `method`, `caching strategy`,
+`deduplication`, etc. This information is stored as a template for later use.
+
+```ts
+const request = client.createRequest()({
+ // Here are some basic options
+ // highlight-start
+ endpoint: "/some-endpoint",
+ method: "POST",
+ deduplicate: true,
+ // highlight-end
+});
+```
+
+(@import core RequestOptionsType type=returns)
+
+---
+
+### Payload
+
+When you want to send some data along with the request, you can use the `setPayload` method. This can be a json,
+FormData or other format - depending on the adapter you use.
+
+First we define request expecting proper type.
+
+```ts
+const postUser = client.createRequest<{
+ response: UserModel;
+ // highlight-start
+ payload: UserPostDataType;
+ // highlight-end
+}>()({
+ method: "POST",
+ endpoint: "/users",
+});
+
+const postFile = client.createRequest<{
+ // highlight-start
+ payload: FormData;
+ // highlight-end
+}>()({
+ method: "POST",
+ endpoint: "/files",
+});
+```
+
+```ts
+// Regular data
+const response = await postUser.setPayload({ name: "John", age: 18 }).send();
+```
+
+You can also pass payload directly to the `send` method.
+
+```ts
+const response = await postFile.send({ payload: data });
+```
+
+
+
+#### Payload with files
+
+When you want to send a file, you can use the `FormData`.
+
+```ts
+// Form data
+const data = new FormData();
+const file = new File([], "file.txt");
+data.append("file", file);
+
+const response = await postFile.setPayload(data).send();
+```
+
+
+
+---
+
+### Parameters
+
+Parameters are the URL parts used to identify a specific resource. In HyperFetch they are defined in the endpoint part
+with `:` prefix. For example:
+
+```ts
+const getNote = client.createRequest()({
+ endpoint: "/note/:noteId", // noteId is a parameter
+});
+const getCategory = client.createRequest()({
+ endpoint: "/category/:categoryId", // categoryId is a parameter
+});
+const getCategoryNote = client.createRequest()({
+ endpoint: "/category/:categoryId/note/:noteId", // categoryId and noteId are parameters
+});
+```
+
+When you have properly prepared requests that expect parameters, you can add parameters using the `setParams` method. In
+generic TypeScript, these parameters will match the endpoint parameters by using literal types and will require literal
+types.
+
+```tsx
+getNote.setParams({ noteId: 1 });
+getCategory.setParams({ categoryId: 2 });
+getCategoryNote.setParams({ categoryId: 2, noteId: 1 });
+```
+
+You can also pass parameters directly to the `send` method.
+
+```ts
+const response = await getCategoryNote.send({ params: { categoryId: 1, noteId: 2 } });
+```
+
+
+
+---
+
+### Query parameters
+
+Query parameters are used to filter or sort the data. In Http requests they are defined in the endpoint part with `?`
+prefix. For example `?search=John&sort=age`.
+
+We can set query params with the `setQueryParams` method.
+
+```ts
+const getUsers = client.createRequest<{
+ // highlight-start
+ queryParams?: { search?: string; sort?: string };
+ // highlight-end
+}>()({
+ endpoint: "/users",
+});
+```
+
+```tsx
+const response = await getUsers.setQueryParams({ search: "John" }).send();
+```
+
+Note that we use `?:` prefix to make query params optional. We can make it required as a whole but also particular
+params from the set.
+
+:::note Required Query Params
+
+You can make query params required by specifying them without `?:` prefix.
+
+```ts
+// All params are required before request is sent
+const getUsers = client.createRequest<{
+ // highlight-start
+ queryParams: { search: string; sort: string };
+ // highlight-end
+}>()({
+ endpoint: "/users",
+});
+
+// Typescript error - sort is required
+// error-start
+const response = await getUsers.setQueryParams({ search: "John" }).send();
+// error-end
+
+// Typescript error - search is required
+// error-start
+const response = await getUsers.setQueryParams({ sort: "age" }).send();
+// error-end
+
+// Typescript error - query params are required
+// error-start
+const response = await getUsers.send();
+// error-end
+```
+
+:::
+
+```tsx
+getUsers.setQueryParams({ search: "John", sort: "age" });
+```
+
+The encoding type for arrays and other options can be set up in the Client. You can also provide your own encoding
+logic.
+
+```tsx
+getUsers.setQueryParams({ search: "John", sort: "age" });
+```
+
+
+
+---
+
+### Adapter Options
+
+You can pass adapter options down with the request options.
+
+```ts
+const request = client.createRequest()({
+ endpoint: "/some-endpoint",
+ // highlight-start
+ // Here are adapter options for the Http adapter (default one)
+ options: { timeout: 1000, withCredentials: true },
+ // highlight-end
+});
+```
+
+:::info
+
+Adapter options may vary depending on the adapter you use.
+
+:::
+
+---
+
+## Methods
+
+The `Request` class offers a suite of methods to configure and interact with a request instance. You can find a
+comprehensive list of these methods and their detailed descriptions in the API reference.
+
+
+
+(@import core Request type=methods&display=table)
+
+
+
+
+
+It is crucial to understand how these methods operate to ensure predictable behavior:
+
+:::danger Methods Return Clones
+
+Most methods on a `Request` instance (e.g., `setParams`, `setData`, `setHeaders`) do not modify the original request
+instance in place. Instead, they return a **new, cloned instance** of the request with the specified modifications
+applied. The original request instance remains unchanged.
+
+Always use the returned new instance for subsequent operations or for sending the request. This immutable approach
+ensures isolation between different request configurations and is fundamental to how Hyper Fetch manages request states
+for features like caching and queueing.
+
+:::
+
+```tsx
+const initialRequest = getUser;
+// ❌ WRONG - Original request (getUser) remains unchanged
+initialRequest.setParams({ userId: 1 }); // setParams returns a new request instance
+// 'initialRequest' still refers to the original getUser without params.
+
+// Sends the original request without params, likely leading to an error.
+const { data, error } = await initialRequest.send();
+```
+
+```tsx
+// ✅ CORRECT - Use the returned (cloned) instance
+const originalRequest = getUser;
+
+// Assign the new, cloned request with parameters to a new variable
+const requestWithParams = originalRequest.setParams({ userId: 1 });
+
+// Send the correctly configured request
+const { data, error } = await requestWithParams.send(); // Success!
+
+// ✅ Also correct (method chaining creates and passes clones implicitly)
+const { data: chainedData, error: chainedError } = await getUser
+ .setParams({ userId: 1 }) // .setParams returns a clone
+ .send(); // .send operates on the final configured clone
+```
+
+---
+
+## Keys
+
+Each `Request` instance is assigned several unique identifiers, known as **keys**. These keys are essential for internal
+mechanisms—such as caching, queueing, request cancellation, deduplication, effect management and many more. Think of
+them as "fingerprints" that help Hyper Fetch track, manage, and use for assigning side-effects to requests.
+
+:::note Keys are generated automatically
+
+Keys are generated automatically based on the request's endpoint, method, and parameters. Currently there are two types
+of the generation mechanisms - simple and complex keys. Complex keys include query params in the generation - simple
+keys include only endpoint and method.
+
+:::
+
+### `queryKey`
+
+General identifier for the request, used for query management (e.g., refetching, optimistic updates, invalidation).
+
+```ts
+const key = request.queryKey;
+```
+
+Set custom key with `setQueryKey` method.
+
+```ts
+const customRequest = request.setQueryKey("custom-key");
+```
+
+
+
+---
+
+### `cacheKey`
+
+Determines how the response is stored and retrieved from the cache. Ensures correct data is cached and served.
+
+```ts
+const key = request.cacheKey;
+```
+
+Set custom key with `setCacheKey` method.
+
+```ts
+const customRequest = request.setCacheKey("custom-key");
+```
+
+
+
+---
+
+### `abortKey`
+
+Identifies and manages ongoing requests for cancellation (e.g., aborting in-flight requests).
+
+```ts
+const key = request.abortKey;
+```
+
+Set custom key with `setAbortKey` method.
+
+```ts
+const customRequest = request.setAbortKey("custom-key");
+```
+
+
+
+---
+
+#### Generation mechanism
+
+By default, these keys are auto-generated based on the request's endpoint, method, and parameters. This ensures that
+each unique request configuration is tracked separately. Your can override this mechanism by providing your own
+implementation.
+
+```tsx
+import { client } from "./api";
+
+client.setCacheKeyMapper((request) => {
+ if (request.requestOptions.endpoint === "/users/:userId") {
+ return `CUSTOM_CACHE_KEY_${request.params?.userId || "unknown"}`;
+ }
+});
+```
+
+#### Why override keys?
+
+In most cases, the default keys are sufficient. However, you may want to override them for advanced scenarios, such as:
+
+- **Custom cache strategies**: Grouping multiple endpoints under a single cache key.
+- **Manual request deduplication**: Treating different requests as identical for deduplication or cancellation.
+- **Abort groups**: Being able to abort multiple requests at once.
+
+#### Overriding keys
+
+You can override any key using the corresponding method:
+
+```ts
+const customRequest = request.setQueryKey("custom-key");
+const customCacheRequest = request.setCacheKey("my-cache-key");
+const abortableRequest = request.setAbortKey("my-abort-key");
+const effectLinkedRequest = request.setEffectKey("my-effect-key");
+```
+
+> **Note:** Overriding keys is an advanced feature. Make sure you understand the implications for caching,
+> deduplication, and request management.
+
+
+
+---
+
+## Features
+
+The `Request` class is packed with features to streamline your data fetching and management. Here are some key
+capabilities:
+
+1. ### Cancellation
+
+Cancellation allows you to abort an in-progress request before it completes. This is useful in scenarios where the
+result of a request is no longer needed, such as when a user navigates away from a page or changes a filter before the
+previous request finishes. Aborting a request helps prevent unnecessary processing and side effects from outdated
+responses.
+
+1. #### Manual cancellation
+
+Triggered by the `.abort()` request method, allow us to stop the request execution.
+
+```tsx live title="Manual cancellation"
+import { getUser } from "./api";
+
+// Start the request
+const response = getUser.send();
+
+setTimeout(() => {
+ // Cancel the request by its abortKey
+ getUser.abort();
+ // Show a toast notification
+ toast({ title: "Cancelled", message: "This request was cancelled manually" });
+}, 1000);
+```
+
+2. #### Automatic cancellation
+
+It is automatically executed when we send two identical requests at the same time. Older request will be cancelled and
+the new one will be sent.
+
+```tsx live title="Automatic cancellation"
+import { getUser } from "./api";
+
+const cancelableRequest = getUser.setCancelable(true);
+
+cancelableRequest.send();
+
+setTimeout(() => {
+ cancelableRequest.send();
+}, 1000);
+```
+
+
+
+---
+
+2. ### Queueing
+
+Queueing ensures that requests are sent one after another, rather than in parallel. When enabled, each request waits for
+the previous one to finish before starting. This is important for operations that must be performed in order, or when
+interacting with APIs that require serialized access.
+
+```tsx live title="Queueing"
+import { postFile } from "./api";
+
+// Queue requests to be sent one-by-one
+const queuedRequest = postFile.setQueued(true);
+queuedRequest.send();
+// This will wait until the previous with th same queryKey one finishes
+queuedRequest.send();
+```
+
+
+
+---
+
+3. ### Offline Support
+
+Offline support allows requests to be stored when the application is offline. These requests are automatically retried
+once the network connection is restored. This feature is useful for applications that need to function reliably in
+environments with intermittent connectivity.
+
+```tsx live title=Offline handling
+import { client, getUser } from "./api";
+
+// Simulate the connection loss
+client.appManager.setOnline(false);
+
+// Trigger the request being offline
+getUser.setOffline(true).send();
+
+// Return back online and the request will be resumed
+setTimeout(() => {
+ client.appManager.setOnline(true);
+}, 2000);
+```
+
+
+
+---
+
+4. ### Deduplication
+
+Deduplication prevents multiple identical requests from being sent at the same time. If a request is already in
+progress, additional requests with the same parameters will reuse the ongoing request and share its response. This
+reduces redundant network traffic and ensures consistent results.
+
+```tsx live
+import { getUser } from "./api";
+
+const getUserDeduplicated = getUser.setDeduplicate(true);
+
+// First request
+getUserDeduplicated.send();
+
+// Second request (Deduplicated - it will never be triggered)
+getUserDeduplicated.send();
+
+// Third request (Deduplicated - it will never be triggered)
+setTimeout(() => {
+ getUserDeduplicated.send();
+}, 500);
+```
+
+
+
+---
+
+5. ### Authentication
+
+Authentication integrates the request with the client's authentication mechanism. When enabled, authentication tokens or
+credentials are automatically included with the request. This is necessary for accessing protected resources or APIs
+that require user identity.
+
+```tsx
+// Add the onAuth interceptor
+client.onAuth(({ request }) => {
+ // Modify request - by adding the auth token to the headers
+ request.setHeaders({
+ Authorization: `Bearer ${auth.token}`,
+ });
+
+ return request;
+});
+
+// Authenticated request (uses Client's auth setup)
+const authRequest = client.createRequest()({ endpoint: "/profile", auth: true });
+
+// it will authenticate the request
+authRequest.send();
+```
+
+
+
+---
+
+6. ### Mapping
+
+**Response mapping** allows you to transform the request payload before sending it, or the response data after receiving
+it. This is useful for adapting data formats between your application and external APIs, or for preprocessing data for
+validation or display.
+
+```tsx
+// Map response data to a new structure
+const { data: mappedResponse } = await client
+ .createRequest<{ response: { name: string } }>()({ endpoint: "/user" })
+ .setResponseMapper((res) => ({ ...res, data: { displayName: res.data.name } }))
+ .send();
+
+console.log(mappedResponse); // { displayName: "John" }
+```
+
+
+
+**Request mapping** provides hooks for custom transformations of payloads, requests, and responses. This allows for
+complex data processing scenarios, such as chaining multiple transformations, integrating with third-party services, or
+adapting to evolving API contracts.
+
+```tsx
+// Advanced mapping: transform payload before sending
+const request = client
+ .createRequest<{ payload: { name: string } }>()({ endpoint: "/advanced" })
+ .setPayloadMapper((payload) => ({ ...payload, name: payload.name.toUpperCase() }));
+
+// Will send the request with the payload { name: "JOHN" }
+const mappedRequest = request.setPayload({ name: "john" }).send();
+```
+
+
+
+---
+
+7. ### Retries
+
+Retries automatically resend a request if it fails due to network errors or server issues. You can configure the number
+of retry attempts and the delay between them. This feature helps improve reliability in the face of transient errors.
+
+```tsx
+// Retry failed requests automatically
+const retryRequest = client.createRequest()({ endpoint: "/unstable", retry: 2, retryTime: 1000 });
+retryRequest.send(); // Will retry up to 2 times on failure
+```
+
+
+
+---
+
+8. ### Error handling
+
+Error handling provides mechanisms to detect and respond to errors that occur during the request lifecycle. You can
+define callbacks for different error types, such as network failures, validation errors, or server responses, allowing
+your application to handle failures appropriately.
+
+```tsx
+// Handle errors with onError callback
+const errorRequest = client.createRequest()({ endpoint: "/fail" });
+
+// Will return error without throwing it
+const { error } = await errorRequest.send();
+
+// You can also handle the error with callback
+await errorRequest.send({
+ onError: ({ response }) => {
+ console.error("Request failed:", response.error);
+ },
+});
+```
+
+
+
+---
+
+9. ### Validation
+
+Validation enables you to check the request data before it is sent, and the response data after it is received. This
+helps ensure that only valid data is processed by your application, and that errors are caught early in the data flow.
+
+```tsx
+// Validate request data before sending
+const validatedRequest = client
+ .createRequest<{ payload: { age: number } }>()({ endpoint: "/validate" })
+ .setRequestMapper((req) => {
+ if (req.payload.age < 18) throw new Error("Must be 18+");
+ return req;
+ });
+const { error } = await validatedRequest.setPayload({ age: 16 }).send();
+
+console.log(error); // Error: Must be 18+
+```
+
+
+
+---
+
+## Lifecycle listeners
+
+The `send()` method accepts an options object where you can define lifecycle callback functions. These callbacks allow
+you to hook into various stages of the request's lifecycle—such as `onBeforeSent` (when the request finishes, regardless
+of outcome), `onSuccess`, `onError`, `onStart`, `onProgress`, `onAbort`, and `onOfflineError`—to perform actions based
+on the request's progress and outcome.
+
+```tsx
+await someRequest.send({
+ onBeforeSent: ({ response, requestId }) => {
+ console.log(`Request ${requestId} has settled. Final response:`, response);
+ // Called right before the request is sent—useful for quickly accessing the requestId for tracking or logging
+ },
+ onStart: ({ requestId, request }) => {
+ console.log(`Request ${requestId} has started.`);
+ // Called when the request is started—useful for showing a loading indicator
+ },
+ onUploadProgress: ({ progress, timeLeft, sizeLeft, total, loaded, startTimestamp, request, requestId }) => {
+ console.log(`Request ${requestId} upload progress:`, progress);
+ // Called when the upload progress is updated—useful for showing a progress bar
+ },
+ onDownloadProgress: ({ progress, timeLeft, sizeLeft, total, loaded, startTimestamp, request, requestId }) => {
+ console.log(`Request ${requestId} download progress:`, progress);
+ // Called when the download progress is updated—useful for showing a progress bar
+ },
+ onResponse: ({ response, requestId }) => {
+ console.log(`Request ${requestId} finished with data:`, response.data);
+ // Called when the request succeeds—useful for processing successful data
+ },
+ onRemove: ({ request, requestId }) => {
+ console.log(`Request ${requestId} removed.`);
+ // Called when the request is removed—useful for cleaning up
+ },
+});
+```
+
+---
+
+## TypeScript
+
+When creating a request with `client.createRequest`, you can specify up to four generic types to ensure type safety and
+enhance the developer experience throughout the request lifecycle:
+
+- **`response`**: The expected type of the successful response data from the server.
+- **`payload`**: The type of the data to be sent in the request body.
+- **`error`**: The type for errors specific to this request, often used for local validation or business logic errors,
+ complementing the global error type defined on the `Client`.
+- **`queryParams`**: The expected structure and types for the request's query parameters.
+
+```tsx
+const request = client.createRequest<{
+ response: { name: string };
+ payload: { age: number };
+ error: { message: string };
+ queryParams: { search: string };
+}>()({ endpoint: "/user" });
+
+const { data, error } = await request.send();
+
+console.log(data); // { name: "John" }
+console.log(error); // undefined
+```
+
+:::warning Install Eslint plugin
+
+To ensure type safety, we recommend installing the
+[eslint-plugin-hyper-fetch](https://www.npmjs.com/package/eslint-plugin-hyper-fetch) plugin. It will help you catch type
+errors early and build robust, maintainable data flows.
+
+Learn how to install and configure the plugin in the [Eslint plugin guide](/docs/integrations/plugin-eslint).
+
+:::
+
+---
+
+### Generics
+
+Starting from `Hyper Fetch v7.0.0`, all the types for the `Client` class and the `createRequest` method are passed as
+objects. This way, user can specify **only** what they want, in any order, in very a readable way.
+
+```ts
+const client = new Client<{ error: ErrorType }>({ url });
+
+const getUsers = client.createRequest<{ response: ResponseType; queryParams: QueryParamsType }>()({
+ endpoint: "/users",
+});
+```
+
+:::caution
+
+We firmly believe that it is more readable approach. Yet, it comes at a cost - currently, TypeScript does not handle
+well the autosuggestions and type inference for the extended object-like generics
+(https://github.com/microsoft/TypeScript/issues/28662). Fear not - the types are working correctly and we found a way to
+make it work with our own eslint plugin.
+
+For example, when writing a request, e.g.:
+
+```ts
+const postUser = client.createRequest<{ invalidGeneric: string }>()({ endpoint: "/" });
+```
+
+TypeScript will not throw an error if you use an invalid key like `invalidGeneric` that isn't part of our API. To catch
+these issues early, we recommend using our custom ESLint plugin. This approach combines the benefits of type safety and
+readability, while ensuring your code uses the correct API syntax.
+
+:::
diff --git a/documentation/docs/documentation/01-getting-started/development.mdx b/documentation/docs/documentation/01-getting-started/development.mdx
deleted file mode 100644
index 0dadf37bd..000000000
--- a/documentation/docs/documentation/01-getting-started/development.mdx
+++ /dev/null
@@ -1,52 +0,0 @@
----
-sidebar_position: 5
-title: Development
-sidebar_label: Development
----
-
-## Structure
-
-1. **Structure** is critically important, so we'll explain how we approach it in HyperFetch. First of all, we create a
- directory for our `client` and its `requests`. We export the prepared elements from this directory.
-
-2. Next, we **create a directory** for each entity in our system (i.e. users, todos, categories, products, groups ...)
- and store our requests.
-
-3. During this setup, we **maintain maximum re-usability**; thanks to the usage of classes and object-oriented approach,
- we can access these elements from anywhere. We can reuse our previously-prepared requests in any component. Also,
- tests have full access without any setup duplication – they use the current settings.
-
-```
-src
-│
-├── api
-│ ├── client.ts
-│ ├── users
-│ │ ├── users.api.ts
-│ │ └── index.ts
-│ ├── products
-│ │ ├── products.api.ts
-│ │ └── index.ts
-│ └── ...
-├── ...
-├── ...
-└── ...
-```
-
----
-
-## Debugging
-
-You can debug apps in one of two ways:
-
-** 1. Use the built-in logger **
-
-Use the client `setDebug(true)` method for this. It will start logging actions in the console. To adjust what type of
-logs will be shown, use `setLoggerSeverity(3)` to get debug logs displayed in the console. Those will show you the exact
-data and information flow in the library while working on your application.
-
-** 2. Create your own logger **
-
-You can create your own dev tools based on events sent from the
-[requestManager](/documentation/02-core/managers.mdx#requestmanager). There is no limitation, and you can receive all
-necessary data to create everything you may need.
diff --git a/documentation/docs/documentation/01-getting-started/environment.mdx b/documentation/docs/documentation/01-getting-started/environment.mdx
deleted file mode 100644
index dce0a930c..000000000
--- a/documentation/docs/documentation/01-getting-started/environment.mdx
+++ /dev/null
@@ -1,41 +0,0 @@
----
-sidebar_position: 7
-title: Environment
-sidebar_label: Environment
----
-
-Hyper Fetch’s core library should work in any JavaScript environment, although sometimes the installation of polyfills
-is required.
-
-For frameworks and libraries, we will release additional packages that enrich core logic and add appropriate facilities
-and API connections for the given environment (as with the addition of hooks in React).
-
----
-
-## Environments
-
-### `✅ Web & PWA`
-
-### `✅ React`
-
-### `✅ React Native`
-
-### `✅ Next.js`
-
-### `✅ Node.js`
-
-### `✅ Svelte`
-
-### `✅ Vue`
-
-## Adapters
-
-### `✅ HTTP / REST`
-
-### `✅ Websockets / Server Sent Events`
-
-### `✅ Firebase`
-
-### `✅ Axios`
-
-### `✅ Graphql`
diff --git a/documentation/docs/documentation/01-getting-started/installation.mdx b/documentation/docs/documentation/01-getting-started/installation.mdx
deleted file mode 100644
index 5d568eb4d..000000000
--- a/documentation/docs/documentation/01-getting-started/installation.mdx
+++ /dev/null
@@ -1,145 +0,0 @@
----
-sidebar_position: 3
-title: Installation
-sidebar_label: Installation
----
-
-import Tabs from "@theme/Tabs";
-import TabItem from "@theme/TabItem";
-
-An installation of Hyper Fetch can be run `clean` or for a specific environment. However, we only currently support
-React.
-
-:::info
-
-The main `@hyper-fetch/core` package is required for other sub packages to work.
-
-:::
-
----
-
-## Typescript
-
-TypeScript is used especially when you want to deploy pure Hyper Fetch logic, without an additional layer of abstraction
-for a specific environment, library, or framework. This gives you access to Hyper Fetch’s base features.
-
-
-
-
-```bash npm2yarn
-npm install --save @hyper-fetch/core
-```
-
-
-
-
-```bash npm2yarn
-yarn add @hyper-fetch/core
-```
-
-
-
-
----
-
-## Sockets
-
-Sockets is created for handling websockets or server sent events.
-
-
-
-
-```bash npm2yarn
-npm install --save @hyper-fetch/sockets
-```
-
-
-
-
-```bash npm2yarn
-yarn add @hyper-fetch/sockets
-```
-
-
-
-
----
-
-## React
-
-React allows the installation of the base library with hooks, offering interfaces that facilitate library usage and
-support the application lifecycle.
-
-
-
-
-```bash npm2yarn
-npm install --save @hyper-fetch/core @hyper-fetch/react
-```
-
-
-
-
-```bash npm2yarn
-yarn add @hyper-fetch/core @hyper-fetch/react
-```
-
-
-
-
-## Firebase adapter
-
-
-
-
-```bash npm2yarn
-npm install --save @hyper-fetch/core @hyper-fetch/firebase
-```
-
-
-
-
-```bash npm2yarn
-yarn add @hyper-fetch/core @hyper-fetch/firebase
-```
-
-
-
-
-## GraphQL adapter
-
-
-
-
-```bash npm2yarn
-npm install --save @hyper-fetch/core @hyper-fetch/graphql
-```
-
-
-
-
-```bash npm2yarn
-yarn add @hyper-fetch/core @hyper-fetch/graphql
-```
-
-
-
-
-## Axios adapter
-
-
-
-
-```bash npm2yarn
-npm install --save @hyper-fetch/core @hyper-fetch/axios
-```
-
-
-
-
-```bash npm2yarn
-yarn add @hyper-fetch/core @hyper-fetch/axios
-```
-
-
-
diff --git a/documentation/docs/documentation/01-getting-started/overview.mdx b/documentation/docs/documentation/01-getting-started/overview.mdx
deleted file mode 100644
index 135798bca..000000000
--- a/documentation/docs/documentation/01-getting-started/overview.mdx
+++ /dev/null
@@ -1,55 +0,0 @@
----
-sidebar_position: 1
-title: Getting Started - Overview
-sidebar_label: Overview
----
-
-# Overview
-
-**`Hyper Fetch`** is an ambitious approach to standardizing data exchange. We develop the logic necessary for performing
-requests, caching, queuing, providing offline support, and enabling persistence for queued requests and caches. Our goal
-is to make Hyper Fetch one of the greatest fetching tools ever made!
-
-
-Our Motivation 🎯
-
-We got the idea for Hyper Fetch after leading several React projects. There are many great fetch libraries (like
-`Axios`, `Fetch`, `SWR`, and `React Query`), but the logic that they provide is detached from each other – i.e. the
-hooks are detached from the fetchers.
-
-This gives users a lot of customization options, but it also comes with some issues. You’d need to build your logic
-every time you start developing a new application. And there is no **schema** for data exchange and normalization, which
-can block future features. We decided to overcome this issue by creating a _straightforward_, _opinionated_, yet
-_flexible_ fetching solution. Hyper Fetch lets you change the parts of your system to make it work as you would like,
-but it’s also more reusable – no more rewriting fetchers (and the whole program flow) with each new application!
-
-With the Hyper Fetch approach, you have a tool that's packed with all sorts of development, testing, and maintenance
-features. It just takes a few minutes to set up, and you're ready to go!
-
-
-
----
-
-### Main Goals 🔮
-
-- ✅ Provide neutral standard for data exchange
-- ✅ Quickly build new solutions without repeating your work or copying it between projects.
-- ✅ Get all the necessary fetching systems – and the possibility of expanding them as needed.
-- ✅ Stop duplicating solutions between and within projects by giving global access to server settings.
-- ✅ Enable rapid application development by setting up a fetcher and its dependencies in minutes, not hours or days.
-- ✅ Trivial tracking of the progress and queue of sent requests.
-- ✅ Provide offline and persistence solutions that no other library offers.
-- ✅ Enhance ease of use by using automation to eliminate common code mistakes.
-
----
-
-### Guides 🪄
-
-Our Guides section provides step-by-step instruction on:
-
-- [Basic](/guides/01-basic/setup.mdx)
-- [Advanced](/guides/02-advanced/cancellation.mdx)
-- [Sockets](/guides/03-sockets/setup.mdx)
-- [Using with React](/guides/04-react/01-core/fetching.mdx)
-- [Using with TypeScript](/guides/05-typescript/global-error.mdx)
-- [Testing](/guides/06-testing/isolation.mdx)
diff --git a/documentation/docs/documentation/01-getting-started/quick-start.mdx b/documentation/docs/documentation/01-getting-started/quick-start.mdx
deleted file mode 100644
index ce471b155..000000000
--- a/documentation/docs/documentation/01-getting-started/quick-start.mdx
+++ /dev/null
@@ -1,98 +0,0 @@
----
-sidebar_position: 4
-title: Quick Start
-sidebar_label: Quick Start
----
-
-import Tabs from "@theme/Tabs";
-import TabItem from "@theme/TabItem";
-
-:::info
-
-The basic version of Hyper Fetch is not associated with any framework or library that is required for it to work.
-
-:::
-
-### 1. Initialize the Client
-
-The first step in implementing Hyper Fetch is to initialize the **[Client](/documentation/02-core/client.mdx)**. It
-manages the basic configuration for connection to the server and all Hyper Fetch’s essential elements (i.e. instances of
-**dispatchers**, **cache**, and **app managers**). Start by determining the `url` of your server.
-
-```tsx title="/src/server/client.ts"
-import { Client } from "@hyper-fetch/core";
-
-export const client = new Client({ url: "http://localhost:3000" });
-```
-
-### 2. Create Requests
-
-Then, having already prepared a connection to the server, we use the client method to create
-**[requests](/documentation/02-core/request.mdx)** and assign types to them.
-
-:::caution
-
-We are using currying to achieve auto generated types for the endpoint string. This solution will be removed once
-[https://github.com/microsoft/TypeScript/issues/10571](https://github.com/microsoft/TypeScript/issues/10571) get
-resolved.
-
-:::
-
-```tsx title="/src/server/auth/auth.ts"
-import { client } from "../client.ts";
-
-type ResponseType = { token: string; refreshToken: string };
-type RequestType = { email: string; password: string };
-
-const postLogin = client.createRequest()({ method: "POST", endpoint: "/auth/login" });
-```
-
-### 3. Use Requests
-
-When you prepare request instances the next step is to use them. You can do it in two ways:
-
-
-
-
-```tsx
-import { useSubmit, useFetch } from "@hyper-fetch/react";
-
-import { postUser, getUsers } from "server/auth";
-
-// Submitting (mutation)
-const { submit, submitting } = useSubmit(postUser.setData({ name: "John" }));
-
-// Trigger submit
-const { data } = await submit();
-
-// Fetching
-const { data, error, loading } = useFetch(getUsers);
-```
-
-
-
-
-```tsx
-import { postLogin } from "server/auth";
-
-...
-
-const handleLogin = async (values: {email: string, password: string}) => {
- const { data, error, status } = await postLogin.send({data: values})
-
- if(data) {
- // perform login
- ...
- } else {
- // handle error
- ...
- }
-
-}
-
-...
-
-```
-
-
-
diff --git a/documentation/docs/documentation/01-getting-started/testing.mdx b/documentation/docs/documentation/01-getting-started/testing.mdx
deleted file mode 100644
index f03d15593..000000000
--- a/documentation/docs/documentation/01-getting-started/testing.mdx
+++ /dev/null
@@ -1,78 +0,0 @@
----
-sidebar_position: 6
-title: Testing
-sidebar_label: Testing
----
-
-Testing is one of the best things in Hyper Fetch. With our architecture and focus on global singleton structure, tests
-can be largely based on the application’s configuration. This means tests are no longer sensitive to micro-changes (like
-changing endpoints or types). Everything reacts and adapts to tests or shows the appropriate error – making tests easier
-to maintain and faster to write.
-
----
-
-## Benefits
-
-- Our setup is always up-to-date with the production solution.
-- No configuration or setup duplication.
-- Easy test maintenance.
-- Faster test builds.
-
----
-
-## Isolation
-
-The `Client` can become a global module, which will cause it to get mixed between test cases from different files if we
-run them in many workers. Thus, we need to isolate it. This takes two steps:
-
-1. ** Clear the Client**
-
-Use the built-in method `.clear()` to ensure client submodules are initialized and clear of any changes.
-
-2. **Clear the node / runner cache**
-
-As you would with Jest, use the built-in method `.resetModules()` to clean the client global module and reinitialize it.
-Depending on the libraries used, you can check out your environment runner methods or try libraries like **decache**.
-
----
-
-## Example
-
-In this example, we’re using the great mocking libraries [msw](https://mswjs.io/) and
-[testing-library](https://testing-library.com/), but this solution works with other libraries like
-[Cypress](https://www.cypress.io/). This allows us to simulate real requests and make our tests as close to the
-production environment as possible. We can thus create a really powerful flow that allows us to easily develop tests.
-
-You can build a utilities set that takes a request and uses its method, endpoint and types to create functions that
-allow you to intercept requests.
-
-```tsx
-import { client } from "../api/client";
-import { getUsers } from "../api";
-
-// 'createInterceptor' is some custom method for handling intercepting in the tests we write
-// In our internal test we used MSW as main intercepting layer
-const getUsersInterceptor = createInterceptor(getUsers, {
- data: [
- { name: "John", age: 18 },
- { name: "Matthew", age: 27 },
- ],
-});
-
-beforeEach(() => {
- // We need to reset modules cache as client is globally exported module
- // This way it will not get mixed-up with other test cases running in parallel
- jest.resetModules();
- // Clean the environment to make sure it's isolated
- client.clear();
-});
-
-it("My test", async () => {
- // Start interceptor listener
- const mock = getUsersInterceptor();
-
- // Handle test
- renderApp();
- expect(await screen.findByText(mock.data[0])).toBeVisible();
-});
-```
diff --git a/documentation/docs/documentation/02-core/adapter.mdx b/documentation/docs/documentation/02-core/adapter.mdx
deleted file mode 100644
index 8aeac222c..000000000
--- a/documentation/docs/documentation/02-core/adapter.mdx
+++ /dev/null
@@ -1,63 +0,0 @@
----
-sidebar_position: 3
-title: Adapter
-sidebar_label: Adapter
----
-
-
-
adapter
-
-
-[Read the API Reference »](/api/Hyper-Fetch/Function/adapter.mdx)
-
-
-
-
----
-
-:::info
-
-`HyperFetch` ships with predefined adapters for the browser and node environments. You do not need to install any
-additional dependencies or event setting up the adapter. **It is ready to use out of the box, with zero configuration
-needed**.
-
-:::
-
-## Introduction
-
-**`Adapter`** is a function that is responsible for communication with the server. The default adapter is used to
-communicate with the REST server. However, there is nothing to prevent you from changing this and creating the adapter
-you need. Thanks to event communication, you can set your own adapter as you wish.
-
-By default, the adapter is responsible for requests, but its role is very significant for many other elements – such as
-tracking the progress of requests, listening for cancellation, and mapping payloads and headers. It also applies to all
-the interceptors in the requesting lifecycle.
-
-:::caution
-
-If there is no XHR in the window object or the XHR object is a polyfill in your environment, you’ll have to install the
-npm package [xmlhttprequest](https://www.npmjs.com/package/xmlhttprequest) and set it on the window object. Otherwise we
-will use the node http module.
-
-:::
-
----
-
-## Preview
-
-{@import Hyper-Fetch adapter preview}
-
----
-
-## Purpose
-
-- Requests handler for client dispatchers
-- Provides flexibility via handler changeability
-
----
-
-## Related guides
-
-- [Custom adapter](/guides/02-advanced/custom-adapter.mdx)
-
----
diff --git a/documentation/docs/documentation/02-core/cache.mdx b/documentation/docs/documentation/02-core/cache.mdx
deleted file mode 100644
index 68171ff23..000000000
--- a/documentation/docs/documentation/02-core/cache.mdx
+++ /dev/null
@@ -1,245 +0,0 @@
----
-sidebar_position: 4
-title: Cache
-sidebar_label: Cache
----
-
-
-
Cache
-
-
-[Read the API Reference »](/api/Hyper-Fetch/Class/Cache.mdx)
-
-
-
-
----
-
-## Introduction
-
-**`Cache`** stores response data from requests. It uses an event system that successively transmits data and takes care
-of validation in the system. Data is stored under `cacheKey` in the storage (which by default is a Map object, but can
-be replaced by any other compatible interface).
-
----
-
-## Purpose
-
-- Stores request results
-- Manages stored data
-- Emits storage events
-
----
-
-## CacheKey
-
-The cache stores data on a `key-value` basis. The key is always specified inside the request as `cacheKey`; it
-determines where the data is stored and is used in propagation of data handling events.
-
-By default, the cacheKey value is auto-determined based on the **method**, **endpoint**, and **query params** of the
-given request. However, there is nothing to prevent you manually adding the key when setting the request or using one of
-its methods.
-
-Thanks to the automatic way of indexing data in the cache, we do not have to worry about paginated keys in the data –
-everything will happen automatically.
-
----
-
-## Events
-
-Available cache events.
-
-{@import Hyper-Fetch getCacheEvents returns}
-
----
-
-## Storage
-
-By default, the cache uses Map as a data retention location. However, you can also choose where the data is stored in
-the system – i.e. local storage or IndexedDB – regardless if the source works synchronously or asynchronously. This
-allows you to set up persistent storage across sessions.
-
-```tsx
-export const client = new Client({
- url: "localhost:3000",
- cache: (instance) =>
- new Cache(instance, {
- storage,
- }),
-});
-```
-
----
-
-## Read Cache
-
-The cache can be read using the `get` method. It returns the data stored under the given key.
-
-```tsx
-const data = client.cache.get("key");
-
-// OR
-
-const getUsers = client.createRequest()({
- method: "GET",
- endpoint: "/users",
-});
-const data = client.cache.get(getUsers.cacheKey);
-
-// OR
-
-const getUsers = client.createRequest()({
- method: "GET",
- endpoint: "/users",
- cacheKey: "CUSTOM_CACHE_KEY",
-});
-const data = client.cache.get("CUSTOM_CACHE_KEY");
-const data = client.cache.get(getUsers.cacheKey);
-
-// OR Dynamic
-
-const getNote = client.createRequest()({
- method: "GET",
- endpoint: "/notes/:noteId",
-});
-const data = client.cache.get(getNote.setParams({ noteId: 1 }).cacheKey);
-```
-
----
-
-## Write Cache
-
-The cache can be written using the `set` method. It stores the data under the given key. We MUST pass the whole request
-to the set method as it stores configuration related to cache time, garbage colletion, etc.
-
-`You can set everything you want, error states, extra data, etc.` The cache will take care of the rest and will emit all
-necessary events. This way our subsystems will receive it and will be able to react to it.
-
-```tsx
-const getNote = client.createRequest()({
- method: "GET",
- endpoint: "/notes/:noteId",
-});
-
-client.cache.set(getNote.setParams({ noteId: 1 }), {
- data: { text: "Hello World" },
- error: null,
- status: 200,
- success: true,
- extra: xhrExtra,
-});
-
-// You can also use callback to read previous data
-
-client.cache.set(getNote.setParams({ noteId: 1 }), (prevData) => ({
- ...prevData,
- data: { text: "Hello World" },
-}));
-```
-
----
-
-## Update Cache
-
-We can update cache by using the `update` method. It updates the data under the given key. We pass the whole request to
-method in similar way as we did it with `set` method.
-
-:::info
-
-Cache will be **NOT** updated if the initial data is not present in the cache.
-
-:::
-
-```tsx
-const getNote = client.createRequest()({
- method: "GET",
- endpoint: "/notes/:noteId",
-});
-
-client.cache.update(getNote.setParams({ noteId: 1 }), {
- data: { text: "Hello World" },
- error: null,
- status: 200,
- success: true,
- extra: xhrExtra,
-});
-
-// You can also use callback to read previous data
-
-client.cache.update(getNote.setParams({ noteId: 1 }), (prevData) => ({
- ...prevData,
- data: { text: "Hello World" },
-}));
-```
-
----
-
-## Delete Cache
-
-To delete data from the cache, we can use the `delete` method. It deletes the data under the given key.
-
-```tsx
-const getNote = client.createRequest()({
- method: "GET",
- endpoint: "/notes/:noteId",
-});
-
-client.cache.delete(getNote.setParams({ noteId: 1 }).cacheKey);
-
-// OR
-
-client.cache.delete("CUSTOM_CACHE_KEY");
-```
-
----
-
-## Invalidate Cache
-
-You can also invalidate the cache by using the `invalidate` method. It deletes the data under the given key and emits
-event, so **in case of using it with for example React, it will refetch the data**.
-
-```tsx
-const getNote = client.createRequest()({
- method: "GET",
- endpoint: "/notes/:noteId",
-});
-
-client.cache.invalidate(getNote.setParams({ noteId: 1 }).cacheKey);
-
-// OR
-
-client.cache.invalidate("CUSTOM_CACHE_KEY");
-
-// OR via RegExp
-
-client.cache.invalidate(new RegExp("CUSTOM_CACHE_KEY"));
-```
-
----
-
-## Persistence
-
-We can achieve the persistence of stored data by changing the cache storage to persistent. It must match the provided
-interface.
-
-#### [Read More](/guides/02-advanced/persistence.mdx)
-
-:::info
-
-Currently there is no cross-tab synchronization. It's planned for a future release.
-
-:::
-
----
-
-## Lifecycle
-
-Cache options can be provided with some lifecycle methods. These are events such as `onInitialization`.
-
----
-
-## Parameters
-
-Configuration options
-
-{@import Hyper-Fetch CacheOptionsType returns}
diff --git a/documentation/docs/documentation/02-core/client.mdx b/documentation/docs/documentation/02-core/client.mdx
deleted file mode 100644
index 343d909f6..000000000
--- a/documentation/docs/documentation/02-core/client.mdx
+++ /dev/null
@@ -1,291 +0,0 @@
----
-sidebar_position: 1
-title: Client
-sidebar_label: Client
----
-
-
-
Client
-
-
-[Read the API Reference »](/api/Hyper-Fetch/Class/Client.mdx)
-
-
-
-
----
-
-## Introduction
-
-**`Client`** is a class that allows you to configure the server connection. It initializes the entire library’s
-subsystems, such as `queues`, `caches`, and `interceptors`. It also allows you to create (based on its settings) the
-requests necessary to execute requests. This way the data and information flow remains locked inside a given client; it
-is isolated and does not affect other clients.
-
-It was designed to be used as a singleton, where `Client` helps us create a global structure for making server requests
-without duplicating logic in different parts of the application. In this approach, we can easily create a solid
-structure and architecture for an application. This also facilitates test maintenance by dividing the necessary
-configurations and types.
-
----
-
-## Purpose
-
-- Orchestrates the components and flow of the library
-- Creates requests to provide global setup and environment
-- Isolates clients from other clients and their events
-
----
-
-## Related guides
-
-- [Setup](/guides/01-basic/setup.mdx)
-- [Global Defaults](/guides/01-basic/global-defaults.mdx)
-- [Intercepting](/guides/02-advanced/intercepting.mdx)
-
----
-
-## Initialization
-
-```tsx
-import { Client } from "@hyper-fetch/core";
-
-export const client = new Client({ url: "http://localhost:3000" });
-```
-
----
-
-## Setting defaults
-
-Because Hyper Fetch components are created inside Client, you can set global or default system values on it.
-
-### Request default setup
-
-We can use the `setRequestDefaultOptions` method to specify the defaults for every created request.
-
-{@import Hyper-Fetch RequestOptionsType preview}
-
-Add them by:
-
-```ts
-const request = client.setRequestDefaultOptions((options) => {
- if (options.method === "POST") {
- return { timeout: 1000, withCredentials: true };
- } else {
- return options;
- }
-});
-```
-
-### Adapter defaults setup
-
-:::info
-
-Adapter options may vary depending on the adapter you use.
-
-:::
-
-We can use the `setAdapterDefaultOptions` method to specify the defaults for every request.
-
-Default HTTP adapter options:
-
-```ts
-{
- timeout: number;
- withCredentials: boolean;
- responseType: "text" | "document" | "arraybuffer" | "blob" | "json";
-}
-```
-
-Add them by:
-
-```ts
-const request = client.setAdapterDefaultOptions({ timeout: 1000, withCredentials: true });
-```
-
----
-
-## Features
-
-### Authentication
-
-To send authenticated requests, set up the `onAuth` interceptor. Set up the request with the `auth` option set to
-**true**. Read more about authentication here.
-
-[Read More](/guides/01-basic/authentication.mdx)
-
-### Pre-Request Interceptor
-
-Use the `onRequest` client method if you need to use the pre-request interceptor to modify the request before it’s sent.
-
-### Post-Request Interceptors
-
-There are several methods for intercepting a response from a request:
-
-- `onError` which is triggered on request error response.
-- `onSuccess` which is triggered on request success response.
-- `onResponse` which is triggered on any response.
-
-We can modify received data with these interceptors before it will be emitted to other sub-systems.
-
-### Query Params
-
-Client has a built-in query params encoding function; you can modify its options or provide your own function. Use the
-`setQueryParamsConfig` method and the options listed below.
-
-{@import Hyper-Fetch QueryStringifyOptionsType returns}
-
-To change the encoding function, use the `setStringifyQueryParams` method.
-
-```tsx
-client.setStringifyQueryParams((value: string) => encode(value));
-```
-
-### Header Mapper
-
-By default, the header mapper behaves very simply: it checks if the content is FormData or JSON, and provides correct
-headers to the request. You can create much more advanced setups with the `setHeaderMapper`. It allows you to define
-custom logic that will be triggered before every request made in the client.
-
-### Payload Mapper
-
-The payload mapper’s default responsibility is to check if data is an instance of FormData or not. Based on this, you
-can stringify non-FormData values or just pass the FormData to the request to be made. This allows file upload to be
-supported out of the box.
-
----
-
-## Typescript
-
-Client has two generic types.
-
-```tsx
-class Client
-```
-
-- `GlobalErrorType` defines the error type used in all the requests. It should consist of an `Error` type and your
- default `ServerErrorType`. For some request’s individual error types, you can set up a `LocalErrorType` for each
- request.
-
-- `AdapterOptions` is the generic responsible for shaping options passed to the adapter. Most likely you will change it
- only when you provide your custom adapter.
-
----
-
-## Components
-
-### [Cache](/api/Hyper-Fetch/Class/Cache.mdx)
-
-Handles data storages and persistence. Can be adjusted with options when initializing `Client`.
-
----
-
-### [Adapter](/api/Hyper-Fetch/Function/adapter.mdx)
-
-Handles all requests within `Client`. Can be replaced with `setAdapter` method.
-
----
-
-### [SubmitDispatcher](/api/Hyper-Fetch/Class/Dispatcher.mdx)
-
-Handles the mutation requests and queueing. Can be adjusted with options when initializing the client.
-
----
-
-### [FetchDispatcher](/api/Hyper-Fetch/Class/Dispatcher.mdx)
-
-Handles the fetching requests and queueing. Can be adjusted with options when initializing the client.
-
----
-
-### [AppManager](/api/Hyper-Fetch/Class/AppManager.mdx)
-
-Handles the app focus and online state. Can be adjusted with options when initializing the client.
-
----
-
-### [RequestManager](/api/Hyper-Fetch/Class/RequestManager.mdx)
-
-Handles additional events and cancellation of requests. Can be adjusted with options when initializing the client.
-
----
-
-### [LoggerManager](/api/Hyper-Fetch/Class/LoggerManager.mdx)
-
-Handles the logging systems for debugging.
-
----
-
-## Parameters
-
-Configuration options
-
-{@import Hyper-Fetch ClientOptionsType returns}
-
-
-
-
-
-
diff --git a/documentation/docs/documentation/02-core/effect.mdx b/documentation/docs/documentation/02-core/effect.mdx
deleted file mode 100644
index 814c4a4de..000000000
--- a/documentation/docs/documentation/02-core/effect.mdx
+++ /dev/null
@@ -1,48 +0,0 @@
----
-sidebar_position: 9
-title: Effect
-sidebar_label: Effect
----
-
-
-
RequestEffect
-
-
-[Read the API Reference »](/api/Hyper-Fetch/Class/RequestEffect.mdx)
-
-
-
-
----
-
-## Introduction
-
-**`RequestEffect`** is basically a set of reducers reacting to the request lifecycle. You can assign it to the Client;
-its `effectKey` has to be the same as the request's effect key so you can match it.
-
-The strength of `RequestEffect` lies in cooperation options with persistent queues. Imagine that you always want to
-trigger some logic when the request is successful, but you must also use persistent storage to save ongoing requests.
-But when the app gets relaunched, there is no way to persist functions and logic. Here, the effect is the solution. We
-can assign it on Client creation so that it will instantly match all ongoing requests from previous sessions.
-
----
-
-## Purpose
-
-- Persists request side-effects
-- Manipulates the lifecycle and allows hooking in
-
----
-
-## EffectKey
-
-A key needed to match the Effect with the request where it's stored. This is automatically generated (like other keys in
-the request), but you can set up custom values for easier usage and matching.
-
----
-
-## Parameters
-
-Configuration options
-
-{@import Hyper-Fetch RequestEffectOptionsType returns}
diff --git a/documentation/docs/documentation/02-core/managers.mdx b/documentation/docs/documentation/02-core/managers.mdx
deleted file mode 100644
index 634d8b875..000000000
--- a/documentation/docs/documentation/02-core/managers.mdx
+++ /dev/null
@@ -1,124 +0,0 @@
----
-sidebar_position: 8
-title: Managers
-sidebar_label: Managers
----
-
-The library contains several managers, they are mainly used to support smaller subsystems and features.
-
----
-
-## AppManager
-
-
-
AppManager
-
-
-[Read the API Reference »](/api/Hyper-Fetch/Class/AppManager.mdx)
-
-
-
-
-
-This class is responsible for the application’s `online` or `offline` state and whether the application window is
-`focused` or `blurred`.
-
-For example, suppose you want to use Hyper Fetch in a React Native environment and the default web browser events won't
-work. In that case, you need to set the events that are most optimal for the current environment.
-
-:::info
-
-Hyper Fetch event listeners return unmounting callbacks for easier cleanup handling.
-
-:::
-
-```tsx
-const unmountFocusListener = client.requestManager.events.onFocus(console.log);
-const unmountOfflineListener = client.requestManager.events.onOffline(console.log);
-
-...
-
-unmountFocusListener()
-unmountOfflineListener()
-```
-
-### Events
-
-{@import Hyper-Fetch getAppManagerEvents returns}
-
----
-
-## RequestManager
-
-
-
RequestManager
-
-
-[Read the API Reference »](/api/Hyper-Fetch/Class/RequestManager.mdx)
-
-
-
-
-
-
-The `RequestManager` is responsible for holding the cancellation tokens needed to terminate the requests and for the
-events related to the requests lifecycle - request `start`, `upload`, `download`, `response` and `abort`.
-
-:::info
-
-Hyper Fetch event listeners return unmounting callbacks for easier cleanup handling.
-
-:::
-
-```tsx
-
-const unmountUploadListener = client.requestManager.events.onUploadProgressById(requestId, console.log);
-const unmountDownloadListener = client.requestManager.events.onDownloadProgressById(requestId, console.log);
-
-...
-
-unmountUploadListener()
-unmountDownloadListener()
-```
-
-### AbortKey
-
-Every request added to the dispatcher creates an abort controller for itself. This controller is stored in the Map
-object under abort key with the `requestId`. This lets you abort whole groups of requests using `abortKey` or single
-requests using their `requestId`. By default, `abortKey` is automatically created on request out of its endpoint and
-method, but you can set custom values.
-
-### Events
-
-{@import Hyper-Fetch getRequestManagerEvents returns}
-
-```ts
-client.requestManager.events.onResponse((response, details) => {
- // ...
-});
-```
-
----
-
-## LoggerManager
-
-
-
LoggerManager
-
-
-[Read the API Reference »](/api/Hyper-Fetch/Class/LoggerManager.mdx)
-
-
-
-
-
-
-LoggerManager is the main instance of the Hyper Fetch logging system. You can initiate single loggers based on it in
-subsystems; this allows you to isolate these loggers but still give them access to the parent configuration in the
-Client.
-
-```ts
-const logger = client.loggerManager.init("My Module")
-
-logger.error(...) // output in console => [My Module] Some message
-```
diff --git a/documentation/docs/documentation/02-core/mocker.mdx b/documentation/docs/documentation/02-core/mocker.mdx
deleted file mode 100644
index cf7ca4129..000000000
--- a/documentation/docs/documentation/02-core/mocker.mdx
+++ /dev/null
@@ -1,140 +0,0 @@
----
-sidebar_position: 6
-title: Mocking
-sidebar_label: Mocking
----
-
-## Introduction
-
-**`Request Mocking`** is a feature that allows for stubbing/mocking the response for a given endpoint,
- **keeping the complete request lifecycle and events**.
-
----
-
-## Initialization
-
-You can mock the response via the `request.setMock` method:
-
-```tsx
-const mockedRequest = request.setMock({ data: { test: 1, array: [200, 300, 404] } });
-```
-
-This way, the `mockedRequest` will always return the `data` with value `{ test: 1, array: [200, 300, 404] } }`.
-The `setMock` method accepts an object with the following keys:
-- `data` - data to be returned from request
-- `status` - Sets the response status. This can be a number or a string; the default is `**200**`.
-- `success` - Informs if the request should be successful or not; the default is `**true**`.
-- `config` - Sets additional parameters that tweak the mock even further.
----
-
-
-## Config
-
-The `setMock` method accepts the `config` object, which allows for tweaking our response.
-
-```tsx
- const request = client
- .createRequest()({ endpoint: "shared-base-endpoint" })
- .setMock({
- data: {mocking: 'is fun'},
- status: 200,
- config: {
- requestTime: 40,
- responseTime: 60,
- totalUploaded: 1000,
- totalDownloaded: 1000,
- },
- });
-
-```
-- `timeout` - **boolean** - informs whether it should return a timeout error.
- - `requestTime` - Simulates how long the request to the server should take (in milliseconds).
- - `responseTime` - Indicates how long the response from the server should take (in milliseconds).
-If their combined total takes longer than provided timeout, each value will be automatically adjusted to last half of the timeout time.
-- `totalUploaded` - total number of 'kilobytes' to be uploaded.
-- `totalDownloaded` - total number of 'kilobytes' to be downloaded.
-
-In the example above - the request phase will take 40 milliseconds and during this phase 1000 'kilobytes' will be uploaded (and `onUploadProgress` events will be emitted).
-The response phase will take 60 millisecond and during this phase 1000 'kilobytes' will be downloaded (and `onDownloadProgress` events will be emitted).
-The word `kilobytes` is written in quotation marks as no real data exchange occurs - it is simply to mock events and allow for data stream mocking.
-
-
-## Usage and use cases
-
-The mocker can be used in a few ways.
-1. It can accept an object:
-```tsx
-const mockedRequest = request.setMock({ data: { test: 1, array: [200, 300, 404] } }); // Always returns data: { test: 1, array: [200, 300, 404]
-```
-2. It can accept an array of values. In this case, values will be iterated over cyclically and applied each time a request is executed:
-
-```tsx
- request.setMock([
- { data: { data: [1, 2, 3] }, config: { status: 400, success: false } },
- { data: { data: [1, 2, 3] }, config: { status: 200 } },
- ]);
-
-await request.send() // returns { data: { data: [1, 2, 3] }, config: { status: 400, success: false } }
-await request.send() // returns { data: { data: [1, 2, 3] }, config: { status: 200 } }
-await request.send() // returns { data: { data: [1, 2, 3] }, config: { status: 400, success: false } }
-```
-3. It also accepts methods that have access to the `request` itself. This allows for dynamic mocking, dependent on the passed arguments during execution:
-```tsx
- const mockedRequest = client
- .createRequest()({ endpoint: "/users/:id" })
- .setMock((r) => {
- const { params } = r;
- if (params.id === 11) {
- return { data: [1, 2, 3], config: { status: 222 } };
- }
- return { data: [4, 5, 6] };
- });
-```
-4. The passed method may be asynchronous:
-```tsx
- const mockedRequest = client
- .createRequest>()({ endpoint: "users/:id" })
- .setMock(async (r) => {
- if (r?.params?.id === 1) {
- return { data: [1, 2, 3], config: { status: 222 } };
- }
- return { data: [4, 5, 6] };
- });
-```
-You can also pass a list of functions; the mocker will cycle over them and execute the correct one each time a request is executed.
-
-## Removal
-
-If you need to remove the mocker from a request, use the `removeMock` method. This way mocker is disabled and mock data is removed.
-```tsx
-mockedRequest.removeMock();
-```
-
-
-## Disabling single mocker
-
-Instead of removing mocker, you can also disable mocker and enable mocker at will with the `request.setEnableMocking` method.
-This way if you set mocking data, it will be kept and not removed as in the `removeMock` case.
-
-```tsx
-const mockedRequest = request.setMock({ data: fixture }); // mock is set
-... // Here mocker works as usual
-mockedRequest.setEnableMocking(false); // Mocker is disabled
-... // Request works as usual
-mockedRequest.setEnableMocking(true); // Mocker is enabled once again
-```
-
-## Disabling mocking for all requests
-
-If you want to disable mocking for all requests of a given `client` instance - you can use the `client.setEnableMocking` method.
-This way all related requests will behave 'as usual' and setting/enabling mocks on single requests will not have any effect.
-
-```tsx
-const client = new Client(...);
-const mockedRequest_1 = newClient.createRequest()({ ... }).setMock({ data: fixture1 });
-const mockedRequest_2 = newClient.createRequest()({ ... }).setMock({ data: fixture2 });
-... // Here mocked requests return mocked data.
-client.setEnableMocking(false) // All mocks are disabled
-... // Here requests work as usual
-client.setEnableMocking(true) // All mocks are enabled once again
-```
diff --git a/documentation/docs/documentation/02-core/overview.mdx b/documentation/docs/documentation/02-core/overview.mdx
deleted file mode 100644
index d8b3dd906..000000000
--- a/documentation/docs/documentation/02-core/overview.mdx
+++ /dev/null
@@ -1,64 +0,0 @@
----
-sidebar_position: 0
-title: Core Package Overview
-sidebar_label: Overview
----
-
-_`Hyper Fetch`_ is an ambitious approach to standardizing data exchange. This is an extremely difficult but important
-task that we have faced. Achieving this goal will elevate the capabilities of all of us to a whole new level. We do not
-want to change your approach but to become a neutral standard where you compose your sub-components according to your
-needs and the clear rules we provide.
-
----
-
-## Let's check short code examples
-
-Check for yourself how fast and easy it is to write queries with Hyper Fetch.
-
----
-
-## Simple Request
-
-```ts
-const client = new Client({ url: "https://api.github.com" });
-
-const getRepositoryDetails = client.createRequest()({
- method: "GET",
- url: "/repos/BetterTyped/hyper-fetch",
-});
-
-const { data, error, status, extra } = await getRepositoryDetails.send();
-```
-
----
-
-## React Integration
-
-```tsx
-import { Client } from "@hyper-fetch/core";
-
-const client = new Client({ url: "https://api.github.com" });
-
-const getRepositoryDetails = client.createRequest()({
- method: "GET",
- url: "/repos/BetterTyped/hyper-fetch",
-});
-
-export function RepositoryComponent() {
- const { loading, error, data } = useFetch(getRepositoryDetails);
-
- if (loading) return "Loading data...";
-
- if (error) return `Fetching error: ${error.message}`;
-
- return (
-
-
{data.name}
-
{data.description}
-
{data.subscribers_count}
-
- );
-}
-```
-
-## Congratulations! You're ready to use **Hyper Fetch**! 🎊
diff --git a/documentation/docs/documentation/02-core/request.mdx b/documentation/docs/documentation/02-core/request.mdx
deleted file mode 100644
index b348f358f..000000000
--- a/documentation/docs/documentation/02-core/request.mdx
+++ /dev/null
@@ -1,375 +0,0 @@
----
-sidebar_position: 2
-title: Request
-sidebar_label: Request
----
-
-
-
Request
-
-
-[Read the API Reference »](/api/Hyper-Fetch/Class/Request.mdx)
-
-
-
-
----
-
-## Introduction
-
-**`Request`** is a class that creates a template for requests and all the necessary information needed for their
-creation. Its strength is its strict and predictable data structure. This lets us dump data, save it to storage as a
-JSON, and recreate it later. This approach allows you to develop a full persistence flow; you can easily persist request
-dumps between sessions.
-
-`Request` contains information about its behavior in the queues or cache, data on the server, and information necessary
-to execute a valid request. In combination with TypeScript, this results in a very friendly flow that’s resistant to
-mistakes.
-
-You can trigger a request with the `send` method, which adds a request to the queue and returns the response.
-
----
-
-## Purpose
-
-- Configures request templates
-- Standardizes the system’s data schema
-- Sends requests via dispatchers
-
----
-
-## Related guides
-
-- [Parameters](/guides/01-basic/parameters.mdx)
-- [Query Parameters](/guides/01-basic/query-params.mdx)
-- [Payload](/guides/01-basic/payload.mdx)
-- [Dispatching](/guides/01-basic/dispatching.mdx)
-- [Retries](/guides/01-basic/retries.mdx)
-- [Error handling](/guides/01-basic/error-handling.mdx)
-- [Data mapping](/guides/01-basic/data-mapping.mdx)
-- [Validation](/guides/02-advanced/validation.mdx)
-- [Mapping](/guides/02-advanced/mapping.mdx)
-- [Deduplication](/guides/02-advanced/deduplication.mdx)
-- [Queueing](/guides/02-advanced/queueing.mdx)
-
----
-
-## Initialization
-
-Request should be initialized from the Client instance with `createRequest` method. This passes a shared reference to
-the place that manages communication in the application.
-
-:::caution
-
-Hyper Fetch currently uses currying in the `createRequest` method to achieve auto-generated types for the endpoint
-string. This solution will be changed once [this TypeScript issue](https://github.com/microsoft/TypeScript/issues/10571)
-is resolved.
-
-:::
-
----
-
-## Options
-
-Request contains all the necessary information to make a request. We can use it later to send them with already prepared
-setup saving time and improving our architecture.
-
-`Options are crucial to the successful data exchange.` We have to provide at least the `endpoint` to fulfill minimum
-requirements.
-
-#### Here you can find some examples of possible configurations.
-
-{@import Hyper-Fetch RequestOptionsType returns}
-
-### You can also provide options to the adapter
-
-:::info
-
-Adapter options may vary depending on the adapter you use.
-
-:::
-
-Default HTTP adapter options:
-
-```ts
-{
- timeout: number;
- withCredentials: boolean;
- responseType: "text" | "document" | "arraybuffer" | "blob" | "json";
-}
-```
-
-Add them by:
-
-```ts
-const request = client.createRequest()({
- endpoint: "/some-endpoint",
- options: { timeout: 1000, withCredentials: true },
-});
-```
-
----
-
-## Request building
-
-### Initialize
-
-The process begins with request initialization. At this point, you can configure how the request will behave, but most
-of the configurations are optional. You can also prepare a global configuration in the Client and avoid copying the
-setup between requests.
-
-```ts
-type ResponseType = { success: boolean }
-type PayloadDataType = { name: string }
-
-const postUser = client.createRequest()({
- endpoint: "/some-endpoint",
- headers: {},
- auth: true,
- method: "POST"
- cancelable: false,
- retry: 2,
- retryTime: 1000,
-});
-
-const { data, error } = await postUser.send({ data: { name: "Maciej" } })
-```
-
-### Request Data
-
-Use the `setData` method to instruct any data to be sent to the server.
-
-```ts
-// Regular data
-postUser.setData({ name: "John", age: 18 })
-
-// Form data
-const data = new FormData();
-...
-postFile.setData(data)
-```
-
-### Parameters
-
-Parameters must be defined in request endpoint using `:`
-
-```ts
-const getNote = client.createRequest()({
- endpoint: "/note/:noteId";
-})
-const getCategory = client.createRequest()({
- endpoint: "/category/:categoryId";
-})
-const getCategoryNote = client.createRequest()({
- endpoint: "/category/:noteId";
-})
-```
-
-When you have properly prepared requests that expect parameters, you can add parameters using the `setParams` method. In
-generic TypeScript, these parameters will match the endpoint parameters by using literal types and will require literal
-types.
-
-```tsx
-getNote.setParams({ noteId: 1 });
-getCategory.setParams({ categoryId: 2 });
-getCategoryNote.setParams({ categoryId: 2, noteId: 1 });
-```
-
-### Query parameters
-
-You can set query params with the `setQueryParams` method. With TypeScript, you can set it up to be accepted as strings,
-objects, or a strict interface. The encoding type for arrays and other options can be set up in the Client. You can also
-provide your own encoding logic.
-
-```tsx
-getUsers.setQueryParams({ search: "John", sort: "age" });
-```
-
-### Trigger request
-
-You can perform a request with the `send` method.
-
-```tsx
-// Simple Send
-getNotes.send();
-
-// Chained Send
-getUsers.setQueryParams({ search: "John", sort: "age" }).send();
-
-// Multiple chained Send
-const { data, error } = await getCategory.setParams({ categoryId: 2 }).setQueryParams({ sortNotes: "age" }).send();
-```
-
-#### For usage with **`React`** checkout our [hooks docs](/documentation/04-react/01-overview.mdx).
-
----
-
-## Features
-
-You can read more in the API reference and guides.
-
-### [Cancellation](/guides/02-advanced/cancellation.mdx)
-
-### [Queueing](/guides/02-advanced/queueing.mdx)
-
-### [Offline](/guides/02-advanced/offline.mdx)
-
-### [Deduplication](/guides/02-advanced/deduplication.mdx)
-
-### [Authentication](/guides/01-basic/authentication.mdx)
-
-### [Data Mapping](/guides/01-basic/data-mapping.mdx)
-
----
-
-## Methods
-
-Using methods on a request is different from other classes in Hyper Fetch. This is to ensure isolation between different
-uses, which allows you to avoid overwriting previously-prepared requests and to dynamically generate keys for queues or
-the cache.
-
-:::danger
-
-Using any method on request returns its clone! `We don't return a reference!`
-
-:::
-
-```tsx
-// ❌ WRONG
-
-const request = getUser;
-
-request.setParams({ userId: 1 }); // Returns CLONED request with assigned params
-
-const { data, error } = await request.send(); // Server error - no params
-```
-
-```tsx
-// ✅ Good
-
-const request = getUser;
-
-const requestWithParams = request.setParams({ userId: 1 }); // Returns CLONED request with assigned params
-
-const { data, error } = await requestWithParams.send(); // Success
-```
-
----
-
-## Keys
-
-Each request gets its identifiers – `queueKey`, `cacheKey`, `abortKey`, and `effectKey`. They are needed to determine
-under which key items will be cached, queued, canceled or handled by [Effects](/documentation/02-core/effect.mdx). By
-default, keys are auto-generated based on the current parameters and endpoint and method values. However, you can
-overwrite these values with other methods as needed.
-
----
-
-## Typescript
-
-Client has four generic types built in: `Response`, `Payload`, `Local Error Response`, and `QueryParams`.
-
-```tsx
-type Response = { name: string }; // What's returned from request
-type Payload = { email: string }; // What's send with request
-type LocalError = { nameMessage: string }; // Additional "local" errors like errors for particular form
-type QueryParams = { sort: string; search: string }; // Query params interface
-
-const someRequest = client.createRequest()({
- endpoint: "category/:categoryId",
-});
-
-someRequest.setData(); // Require the 'Payload' type
-someRequest.setParams(); // Require { categoryId: Param } type
-someRequest.setQueryParams(); // Require the 'QueryParams' type
-
-const { data, error } = someRequest.send();
-
-data; // Has 'Response' type
-error; // Has 'GlobalError' or 'LocalError' type
-```
-
----
-
-## Usage
-
-```tsx
-import { client } from "./client";
-
-export const getUsers = client.createRequest()({
- method: "GET",
- endpoint: "/users",
-});
-
-export const getUser = client.createRequest()({
- method: "GET",
- endpoint: "/users/:userId",
-});
-
-export const postUser = client.createRequest()({
- method: "POST",
- endpoint: "/users",
-});
-
-export const patchUser = client.createRequest>()({
- method: "PATCH",
- endpoint: "/users/:userId",
-});
-
-export const deleteUser = client.createRequest()({
- method: "DELETE",
- endpoint: "/users/:userId",
-});
-
-// Usage
-
-const { data, error } = await getUsers.send({ queryParams: { page: 1 } });
-
-const { data, error } = await getUsers.send({ params: { userId: 23 } });
-
-const { data, error } = await postUser.send({ data: { name: "Maciej" } });
-
-const { data, error } = await patchUser.send({ params: { userId: 12 }, data: { name: "Kacper" } });
-
-const { data, error } = await deleteUser.send({ params: { userId: 88 } });
-```
-
----
-
-## Lifecycle listeners
-
-We can easily add lifecycle listeners to the **`send()`** method. This allows us to listen to the request events and
-perform callbacks with the received data for each stage of execution.
-
-{@import Hyper-Fetch FetchSendActionsType returns}
-
-#### Example
-
-```tsx
-await request.send({
- onSettle: (requestId) => {
- console.log(requestId);
- },
-});
-```
-
----
-
-## Parameters
-
-Configuration options for the `client.createRequest()` method.
-
-{@import Hyper-Fetch RequestOptionsType returns}
-
-#### Example
-
-```tsx
-const request = client.createRequest()({
- endpoint: "/some-endpoint",
- retry: 2,
- cancelable: true,
- cacheTime: 20000,
- cacheKey: "users",
- deduplication: true,
-});
-```
diff --git a/documentation/docs/documentation/03-sockets/adapter.mdx b/documentation/docs/documentation/03-sockets/adapter.mdx
deleted file mode 100644
index f169cc674..000000000
--- a/documentation/docs/documentation/03-sockets/adapter.mdx
+++ /dev/null
@@ -1,44 +0,0 @@
----
-sidebar_position: 6
-title: Socket Adapters
-sidebar_label: Adapters
----
-
-
-
-
-
Weboscket Adapter
-
-
-[Read the API Reference »](/api/Sockets/Function/websocketAdapter.mdx)
-
-
-
-
-
-
SSE Adapter
-
-
-[Read the API Reference »](/api/Sockets/Function/sseAdapter.mdx)
-
-
-
-
-
-
----
-
-## Introduction
-
-**`Adapter`** is a class that gives us possibility to interact with servers. The default adapter is used to communicate
-with the `Websocket` or `SSE` server. However, there is nothing to prevent you from changing this and creating the
-adapter you need. Thanks to event communication, you can set your own adapter as you wish by only fulfilling the
-typescript requirements. This way you can create your own adapters for existing libraries like `socket.io`.
-
-## Adapter Imports
-
-{@import Sockets websocketAdapter import}
-
-{@import Sockets sseAdapter import}
-
----
diff --git a/documentation/docs/documentation/03-sockets/emitter.mdx b/documentation/docs/documentation/03-sockets/emitter.mdx
deleted file mode 100644
index d6097c1a6..000000000
--- a/documentation/docs/documentation/03-sockets/emitter.mdx
+++ /dev/null
@@ -1,167 +0,0 @@
----
-sidebar_position: 5
-title: Socket Emitter
-sidebar_label: Emitter
----
-
-
-
Emitter
-
-
-[Read the API Reference »](/api/Sockets/Class/Emitter.mdx)
-
-
-
-
----
-
-## Introduction
-
-**`Emitter`** is a class that creates a template for sending events and stores all the necessary information needed for
-their creation. Its strength is its strict and predictable data structure.
-
-You can trigger a event with the `emit` method, which send data to sever.
-
----
-
-## Purpose
-
-- Configures events templates
-- Standardizes the system’s data schema
-- Sends events to server
-
----
-
-## Initialization
-
-Emitter should be initialized from the Socket instance with `createEmitter` method. This passes a shared reference to
-the place that manages communication in the application.
-
-```tsx
-import { socket } from "./socket";
-
-export const sendChatMessage = socket.createEmitter()({
- endpoint: "chat-message", // endpoint of the event
-});
-
-export const sendUserStatus = socket.createEmitter()({
- endpoint: "status", // endpoint of the event
-});
-```
-
----
-
-## Usage
-
-### Request Data
-
-Use the `setData` method to instruct any data to be sent to the server.
-
-```tsx
-sendChatMessage.setData({ message: "message" });
-```
-
-### Emitting
-
-Use the `emit` method to start the event emitting.
-
-```tsx
-sendChatMessage.emit({ message: "message" });
-
-// or
-
-sendChatMessage.setData({ message: "message" }).emit();
-```
-
-### Acknowledgements
-
-Use the `acknowledgements` by passing the second parameter to the emitting method.
-
-:::caution
-
-**Make sure your server is supporting the acknowledgements!** When using default adapter, make sure you pass the id of
-the event in returning event, when using custom adapters, you have to implement according to it's specification.
-
-:::
-
-```tsx
-sendChatMessage.emit({ data: { messsage: "some message" } }, (error, data) => {
- if (error) {
- alert("No server response!");
- } else {
- alert("Message received on server.");
- }
-});
-```
-
-#### Implementation on sever
-
-After acknowledging the event, the server should **return the event with message id in the response**.
-
-```ts
-import { WSMessageType } from "@hyper-socket/sockets";
-
-const message = {
- title: string;
- description: string;
-}
-
-// On browser
-emitter.emit({
- data: message,
- ack: (data) => {
- console.log(data);
- },
-});
-
-// On server
-socket.on("chat-message", (message: WSMessageType) => {
- // Do something with message
- console.log(message.data);
-
- // Emitting acknowledgement event
- socket.emit({ id: message.id, endpoint: message.endpoint, data: { success: true } })
-});
-```
-
----
-
-## Methods
-
-Using methods on a emitter is different from other classes in Hyper Fetch. This is to ensure isolation between different
-uses, which allows you to avoid overwriting previously-prepared emitters and to dynamically generate keys for queues or
-the cache.
-
-:::danger
-
-Using any method on emitter returns its clone! `We don't return a reference!`
-
-:::
-
-```tsx
-// ❌ WRONG
-
-const emitter = sendMessageEmitter;
-
-emitter.setData({ message: "some message" }); // Returns CLONED emitter with assigned data
-
-emitter.emit(); // Server error - no data
-```
-
-```tsx
-// ✅ Good
-
-const emitter = sendMessageEmitter;
-
-const emitterWithData = emitter.setData({ message: "some message" }); // Returns CLONED emitter with assigned data
-
-emitterWithData.emit(); // Success
-```
-
----
-
-## Parameters
-
-Configuration options
-
-{@import Sockets EmitterOptionsType returns}
diff --git a/documentation/docs/documentation/03-sockets/listener.mdx b/documentation/docs/documentation/03-sockets/listener.mdx
deleted file mode 100644
index 8d2f27ad1..000000000
--- a/documentation/docs/documentation/03-sockets/listener.mdx
+++ /dev/null
@@ -1,207 +0,0 @@
----
-sidebar_position: 4
-title: Socket Listener
-sidebar_label: Listener
----
-
-
-
Listener
-
-
-[Read the API Reference »](/api/Sockets/Class/Listener.mdx)
-
-
-
-
----
-
-## Introduction
-
-**`Listener`** is a class that creates a template for receiving events from server. Its strength is its strict and
-predictable data structure which together with typescript gives a lot of confidence while developing data exchange
-features.
-
-To use the listener we need to trigger the `listen` method with provided callback.
-
----
-
-## Purpose
-
-- Configures events listeners templates
-- Standardizes the system’s data schema
-- Listen to server events
-
----
-
-## Initialization
-
-Listener should be initialized from the Socket instance with `createListener` method. This passes a shared reference to
-the place that manages communication in the application.
-
-```tsx
-import { socket } from "./socket";
-
-export const onChatMessage = socket.createListener()({
- endpoint: "chat-message", // endpoint of the event
-});
-
-export const onUserStatusChange = socket.createListener()({
- endpoint: "status", // endpoint of the event
-});
-```
-
----
-
-## Usage
-
-### Listening
-
-Use the `listen` method to start the listening for incoming events.
-
-```tsx
-onChatMessage.listen({
- callback: (message) => {
- // message have type ChatMessageType
- console.log(message);
- },
-});
-```
-
-### Remove listener
-
-Use the returned method to stop listening.
-
-```tsx
-const removeEvent = onChatMessage.listen({ callback: (message) => console.log(message) });
-
-...
-
-removeEvent() // We remove listener
-```
-
-Remove event listeners directly from the adapter
-
-```tsx
-const callback = (message) => console.log(message);
-const removeEvent = onChatMessage.listen({ callback });
-
-...
-
-socket.adapter.listeners.delete(onChatMessage.endpoint) // We remove ALL listeners from given event
-socket.adapter.listeners.get(onChatMessage.endpoint).delete(callback) // We remove single listener from given event
-```
-
-Listen to event `once`
-
-```tsx
-const removeEvent = onChatMessage.listen({
- callback: (message) => {
- console.log(message);
- removeEvent(); // We listen only to single event
- },
-});
-```
-
----
-
-## Listening with onData hook
-
-You can use `onData` method to listen to all events of given listener. This method is useful when you want to attach
-some logic to any occurrence of the event. It's additional way of hooking into the listener groups.
-
-```ts
-export const onNoteChange = socket
- .createListener()({
- endpoint: "notes/:id",
- })
- .onData((event) => {
- // We will receive all events from given listener,
- // no mater of ID, as it will be filled later on while listening
- console.log(event);
- });
-
-onNoteChange.setParams({ noteId: 1 }).listen(() => {
- // some logic
-});
-
-onNoteChange.setParams({ noteId: 2 }).listen(() => {
- // some logic
-});
-
-// console.log(event) ===> { noteId: 1, ... }
-// console.log(event) ===> { noteId: 2, ... }
-```
-
-### Integration with Hyper Fetch
-
-We can use this to make simple integration with Hyper Fetch. We can use `onData` hook to update the cache with new data
-from the socket.
-
-```ts
-
-// ==> Our core setup
-const client = new Client({ url: "http://localhost:3000" });
-const getNote = client.createRequest()({
- endpoint: "/note/:noteId";
-})
-
-
-// ==> Our realtime listener
-
-export const onNoteChange = socket.createListener()({
- endpoint: "notes",
-}).onData((event) => {
- const { noteId } = event;
-
- // Fill the params so our cache can find the request in storage
- const noteRequest = client.cache.get(getNote.setParams({ noteId }));
-
- // Update the cache
- client.cache.update(noteRequest, (prevData) => {
- return {...prevData, data: event}
- });
-});
-
-```
-
----
-
-## Methods
-
-Using methods on a listener is different from other classes in Hyper Fetch. This is to ensure isolation between
-different uses, which allows you to avoid overwriting previously-prepared listeners and to dynamically generate keys for
-queues or the cache.
-
-:::danger
-
-Using any method on listener returns its clone! `We don't return a reference!`
-
-:::
-
-```tsx
-// ❌ WRONG
-
-const listener = getChatMessageListener;
-
-listener.setOptions({ ... }); // Returns CLONED listener with assigned options
-
-listener.listen(); // Error - no options will be applied
-```
-
-```tsx
-// ✅ Good
-
-const listener = getChatMessageListener;
-
-const listenerWithOptions = listener.setOptions({ ... }); // Returns CLONED listener with assigned options
-
-listenerWithOptions.listen(); // Success - options applied
-```
-
----
-
-## Parameters
-
-Configuration options
-
-{@import Sockets ListenerOptionsType returns}
diff --git a/documentation/docs/documentation/03-sockets/overview.mdx b/documentation/docs/documentation/03-sockets/overview.mdx
deleted file mode 100644
index 256f73aa7..000000000
--- a/documentation/docs/documentation/03-sockets/overview.mdx
+++ /dev/null
@@ -1,61 +0,0 @@
----
-sidebar_position: 1
-title: Sockets Overview
-sidebar_label: Overview
----
-
-Sockets module was created to handle listeners and emitters on open connections. Our base `Hyper Fetch` package was
-created with different approach to things like interceptors or data exchange itself but has some architecture decisions
-in common, like singleton pattern.
-
-## Main Goals 🔮
-
-✅ Neutral standard for data exchange
-
-✅ Architecture to support composing our logic with existing clients like socket.io, firebase, etc.
-
-✅ Possibility to attach own adapters with ease and type safety
-
-✅ Separation of listeners and emitters to clearly split responsibility
-
-✅ SSE and Websocket by default
-
-## Simple examples
-
-Here you can find some simple examples of how to use our sockets module.
-
-#### Initialize Client
-
-```tsx
-import { Socket } from "./socket";
-
-export const socket = new Sockets({
- url: "ws://localhost:3000",
-});
-```
-
-#### Create Listeners
-
-```ts
-import { socket } from "./socket";
-
-export const onChatMessage = socket.createListener()({
- endpoint: "chat-message", // endpoint of the event
-});
-
-onChatMessage.listen({ callback: (data) => console.log(data) });
-```
-
-#### Create Emitters
-
-```tsx
-import { socket } from "./socket";
-
-export const sendChatMessage = socket.createEmitter()({
- endpoint: "chat-message", // endpoint of the event
-});
-
-sendChatMessage.emit({ data: { message: "Hello world" } });
-```
-
-## Congratulations! You're ready to use **Hyper Fetch Sockets**! 🎊
diff --git a/documentation/docs/documentation/03-sockets/socket.mdx b/documentation/docs/documentation/03-sockets/socket.mdx
deleted file mode 100644
index 4c68ece51..000000000
--- a/documentation/docs/documentation/03-sockets/socket.mdx
+++ /dev/null
@@ -1,115 +0,0 @@
----
-sidebar_position: 3
-title: Socket Class
-sidebar_label: Socket
----
-
-
-
Socket
-
-
-[Read the API Reference »](/api/Sockets/Class/Socket.mdx)
-
-
-
-
----
-
-## Introduction
-
-**`Socket`** is a class that allows you to configure the server connection. It initializes the entire library’s
-subsystems, such as `offline`, `events`, and `interceptors`. It also allows to create (based on its settings) the
-listeners and emitters necessary to execute requests. This way the data and information flow remains locked inside a
-given socket - it is isolated and does not affect other sockets.
-
----
-
-## Purpose
-
-- Orchestrates the components and flow of the sockets library
-- Creates listeners and emitters to provide global setup and environment
-- Isolates sockets from other sockets and their events
-
----
-
-## Initialization
-
-```tsx
-import { Socket } from "@hyper-fetch/sockets";
-
-export const socket = new Socket({ url: "ws://localhost:3000" });
-```
-
----
-
-## Features
-
-### Mode
-
-You can pick between two built-in modes for the data exchange.
-
-1. Websocket mode (default)
-2. Server Sent Events mode
-
-You can change it with `SSE` adapter.
-
-```tsx
-import { sseAdapter } from "@hyper-fetch/sockets";
-
-new Sockets({ url: "ws://localhost:3000" }).setAdapter(sseAdapter);
-```
-
-### Authentication
-
-To exchange authenticated events, set up the `auth` parameter with authentication query params. Later on, you can change
-the `auth` value with `setAuth` method, which after setting up the new data will reconnect the socket server. Read more
-about authentication here.
-
-[Read More](/guides/03-sockets/authentication.mdx)
-
-### On-Emitting Interceptors
-
-Use the `onSend` socket method if you need to use the pre-emitting interceptor to modify the `Emitter` before it’s sent.
-
-### On-Message Interceptors
-
-There are few methods for intercepting a response from a request:
-
-- `onError` which is triggered on error from socket.
-- `onMessage` which is triggered on any received message.
-
-We can modify received data with this interceptor before it will be emitted to other sub-systems.
-
-### Query Params
-
-Sockets has a built-in query params encoding function; you can modify its options or provide your own function. Use the
-`queryParamsConfig` method and the options listed below.
-
-{@import Hyper-Fetch QueryStringifyOptionsType returns}
-
-To change the encoding function, use the `queryParamsStringify` method.
-
-```tsx
-export const socket = new Sockets({
- url: "ws://localhost:3000",
- queryParams: { param1: [1, 2, 3], param2: "test" },
- queryParamsStringify: (value: string) => encode(value),
-});
-```
-
----
-
-## Typescript
-
-Sockets has one generic type responsible for the type of the current `Socket Adapter`. It defaults to the built-in
-adapter type.
-
-```tsx
-class Sockets
-```
-
-It needs to fulfill the `SocketAdapterType` interface.
-
-{@import Sockets SocketAdapterType returns}
-
----
diff --git a/documentation/docs/documentation/04-react/02-core/react-native.mdx b/documentation/docs/documentation/04-react/02-core/react-native.mdx
deleted file mode 100644
index 727f614d5..000000000
--- a/documentation/docs/documentation/04-react/02-core/react-native.mdx
+++ /dev/null
@@ -1,82 +0,0 @@
----
-sidebar_position: 2
-title: React Native
-sidebar_label: React Native
----
-
-**`React Native`** is also supported by `Hyper Fetch`. This library was designed to work with many environments, which
-is why we kept the structure of the base library very generic and modular. This means that we can freely replace many of
-the components.
-
----
-
-## Online / Offline status handling
-
-The default events that handle online/offline status in the library are based on the events available in the web browser
-environment. To use mobile device solutions, you can change the code responsible for handling the connection status.
-
-```tsx
-export const client = new Client({
- url: environment.serverUrl,
- appManager: (instance) =>
- new AppManager(instance, {
- initiallyOnline: NetInfo.fetch().then((state) => state.isConnected),
- onlineEvent: (setOnline) =>
- NetInfo.addEventListener((state) => {
- setOnline(state.isConnected);
- }),
- }),
-});
-```
-
----
-
-## Application focus / blur state
-
-You can use similar logic to that used for online/offline status handling to handle functions that perform requests
-during focus (active usage) and blur (inactive) states.
-
-```tsx
-export const client = new Client({
- url: environment.serverUrl,
- appManager: (instance) =>
- new AppManager(instance, {
- focusEvent: (setFocused) =>
- ...,
- blurEvent: (setBlurred) =>
- ...,
- }),
-});
-```
-
----
-
-## Screen focus / blur state
-
-To implement focus/blur logic for a specific screen, you must use custom solutions that track the focus state of the
-screen and hook it into revalidation.
-
-```tsx
-import React from "react";
-import { useFocusEffect } from "@react-navigation/native";
-
-export function useFocusRevalidation(refetch: () => void) {
- const initialized = React.useRef(true);
-
- useFocusEffect(
- React.useCallback(() => {
- if (initialized.current) {
- initialized.current = false;
- } else {
- refetch();
- }
- }, [refetch]),
- );
-}
-```
-
-```tsx
-const { data, error, loading, refetch } = useFetch(getUsers);
-
-useFocusRevalidation(refetch);
-```
diff --git a/documentation/docs/documentation/04-react/02-core/use-app-manager.mdx b/documentation/docs/documentation/04-react/02-core/use-app-manager.mdx
deleted file mode 100644
index eed55811c..000000000
--- a/documentation/docs/documentation/04-react/02-core/use-app-manager.mdx
+++ /dev/null
@@ -1,50 +0,0 @@
----
-sidebar_position: 7
-title: React hooks - useAppManager
-sidebar_label: useAppManager
----
-
-# useAppManager
-
-
-
useAppManager
-
-
-[Read the API Reference »](/api/React/Hook/useAppManager.mdx)
-
-
-
-
----
-
-## Introduction
-
-**`useAppManager`** allows you to use information about the connection status and screen focus state. It also offers
-options to manipulate its global state. This hook uses the [`AppManager`](/documentation/02-core/managers.mdx) available
-on the [`Client`](/documentation/02-core/client.mdx) instance.
-
-It returns the status of `isOnline` and `isFocused` and the actions that allow you to change them.
-
-```tsx
-const { isOnline, setOnline } = useAppManager(client);
-
-setOnline(true);
-```
-
-```tsx
-const { isFocused, setFocused } = useAppManager(client);
-
-setFocused(true);
-```
-
----
-
-## Returns
-
-Returned values from this hook.
-
-```tsx
-const values = useAppManager(client);
-```
-
-{@import React useAppManager returns}
diff --git a/documentation/docs/documentation/04-react/02-core/use-cache.mdx b/documentation/docs/documentation/04-react/02-core/use-cache.mdx
deleted file mode 100644
index 098519586..000000000
--- a/documentation/docs/documentation/04-react/02-core/use-cache.mdx
+++ /dev/null
@@ -1,66 +0,0 @@
----
-sidebar_position: 6
-title: React hooks - useCache
-sidebar_label: useCache
----
-
-# useCache
-
-
-
useCache
-
-
-[Read the API Reference »](/api/React/Hook/useCache.mdx)
-
-
-
-
----
-
-## Introduction
-
-This hook allows us to manipulate the passed request’s [`Cache`](/documentation/02-core/managers.mdx) and receive change
-callbacks. It is important to make sure that `cacheKey` is not affected by auto-generation – that there is a stable
-connection between the hook's request and the cache.
-
-```tsx
-const { data, error, loading, refetch, onSuccess, onError, onFinished } = useCache(getUsers);
-
-onSuccess((payload) => {
- console.log(payload); // [ User, User, User ]
-});
-
-onError((error) => {
- console.log(error); // { message: string }
-});
-
-onFinished(([payload, error, status]) => {
- console.log(payload); // [ User, User, User ] | null
- console.log(error); // { message: string } | null
- console.log(status); // 200 / 400 / 404 / 500 ...
-});
-```
-
----
-
-## Options
-
-Configuration options for this hook provided as a second parameter.
-
-```tsx
-const { ... } = useCache(request, options)
-```
-
-{@import React UseCacheOptionsType returns}
-
----
-
-## Returns
-
-Returned values from this hook.
-
-```tsx
-const values = useCache(request);
-```
-
-{@import React useAppManager returns}
diff --git a/documentation/docs/documentation/04-react/02-core/use-fetch.mdx b/documentation/docs/documentation/04-react/02-core/use-fetch.mdx
deleted file mode 100644
index 70968f20f..000000000
--- a/documentation/docs/documentation/04-react/02-core/use-fetch.mdx
+++ /dev/null
@@ -1,108 +0,0 @@
----
-sidebar_position: 3
-title: React hooks - useFetch
-sidebar_label: useFetch
----
-
-# useFetch
-
-
-
useFetch
-
-
-[Read the API Reference »](/api/React/Hook/useFetch.mdx)
-
-
-
-
----
-
-## Introduction
-
-This hook is created to **retrieve data** from the server. It uses the
-[`Fetch Dispatcher`](/documentation/02-core/dispatcher.mdx) to handle requests and the
-[`Cache`](/documentation/02-core/cache.mdx) to manage the overall state of the data.
-
-A prepared Request is the minimum requirement for useFetch.
-
-If you intend to `mutate` data stored on the server, we recommend choosing the
-[`useSubmit`](/documentation/04-react/02-core/use-submit.mdx) hook.
-
----
-
-## Initialization
-
-```tsx
-const { data, error, loading, onSuccess, onError, onFinished } = useFetch(getUsers);
-```
-
----
-
-## How it works?
-
-**`useFetch`** executes a request when a component is mounted or when its dependencies array changes. It uses dependency
-tracking to limit re-rendering and help with performance.
-
-Under the hood, communication with the core systems is established by event emitters. There are many `"helper hooks"`
-that get returned from the hook, like `onSuccess`, `onError`, and `onFinished` (among others). They will help you handle
-various events in the request flow and lifecycle.
-
-We used this approach to avoid overloading the base hook with callback logic, which causes low code readability and
-increases complexity.
-
-```tsx
-import { useFetch } from "@hyper-fetch/react";
-import { getUsers } from "server";
-
-const UsersListPage: React.FC = () => {
- const { data, error, loading, onSuccess, onError, onFinished } = useFetch(getUsers);
-
- onSuccess(({ response }) => {
- console.log(response); // [ User, User, User ]
- });
-
- onError(({ response }) => {
- console.log(response); // { message: string }
- });
-
- onFinished(({ response }) => {
- const [payload, error, status] = response;
- console.log(payload); // [ User, User, User ] | null
- console.log(error); // { message: string } | null
- console.log(status); // 200 / 400 / 404 / 500 ...
- });
-
- return (
-
- {loading &&
}
- {!loading && error && {error.error_message} }
- {!loading && !error && !data.length && List is empty
}
- {!loading && !error && data.length && {data.map(user =>
{user.name}
)}
}
-
- );
-};
-```
-
----
-
-## Options
-
-Configuration options for `useFetch` must be provided as the second parameter.
-
-```tsx
-const { ... } = useFetch(request, options)
-```
-
-{@import React UseFetchOptionsType returns}
-
----
-
-## Returns
-
-Returned values from this hook.
-
-```tsx
-const values = useFetch(request);
-```
-
-{@import React UseFetchReturnType returns}
diff --git a/documentation/docs/documentation/04-react/02-core/use-queue.mdx b/documentation/docs/documentation/04-react/02-core/use-queue.mdx
deleted file mode 100644
index 9b24fbb1e..000000000
--- a/documentation/docs/documentation/04-react/02-core/use-queue.mdx
+++ /dev/null
@@ -1,94 +0,0 @@
----
-sidebar_position: 5
-title: React hooks - useQueue
-sidebar_label: useQueue
----
-
-# useQueue
-
-
-
useQueue
-
-
-[Read the API Reference »](/api/React/Hook/useQueue.mdx)
-
-
-
-
----
-
-## Introduction
-
-This hook controls the **dispatcher queues**. It uses the [`Dispatcher`](/documentation/02-core/dispatcher.mdx) to read
-the actual value of the queue, which is based on the `queueKey` retrieved from the request passed as the first argument.
-
-A prepared [`Request`](/documentation/02-core/request.mdx) is the minimum requirement for `useQueue`.
-
----
-
-## Initialization
-
-```tsx
-const { requests, stopped, stop, start, pause } = useQueue(getUsers);
-```
-
----
-
-## How it works?
-
-**`useQueue`** uses the request to read the Dispatcher queue value based on its `queueKey`. Events emitted by the
-Dispatcher keep this hook up to date. This hook gives you the option to control every single request made in your
-application and manipulate whole queues and single requests. It works best with the `one-by-one` dispatching mode, when
-the `queued` option is set to true.
-
-:::caution
-
-Remember to make sure your request `queueKey` is static when you use this hook. Because it auto-generates keys, it may
-return wrong values if your request uses params or query params. Providing a custom `queueKey` when the request is
-created will avoid this problem.
-
-:::
-
-```tsx
-const { requests, stopped, stop, start, pause } = useQueue(getUsers);
-
-requests.forEach((req) => {
- req.stopRequest();
- req.startRequest();
-});
-
-stop();
-pause();
-start();
-```
-
-Read more about differences between `stop`, `pause` and `start` in the
-[`Dispatcher`](/documentation/02-core/dispatcher.mdx) doc page.
-
----
-
-## Options
-
-Configuration options for this hook are provided as the second parameter.
-
-```tsx
-const { ... } = useQueue(request, options)
-```
-
-
-
----
-
-## Returns
-
-Returned values from this hook.
-
-```tsx
-const values = useQueue(request);
-```
-
-{@import React useQueue returns}
-
-#### Request interface
-
-{@import React QueueRequest returns}
diff --git a/documentation/docs/documentation/04-react/02-core/use-submit.mdx b/documentation/docs/documentation/04-react/02-core/use-submit.mdx
deleted file mode 100644
index 74de59aba..000000000
--- a/documentation/docs/documentation/04-react/02-core/use-submit.mdx
+++ /dev/null
@@ -1,139 +0,0 @@
----
-sidebar_position: 4
-title: React hooks - useSubmit
-sidebar_label: useSubmit
----
-
-# useSubmit
-
-
-
useSubmit
-
-
-[Read the API Reference »](/api/React/Hook/useSubmit.mdx)
-
-
-
-
----
-
-## Introduction
-
-This hook **mutates data** on the server and supports controlling requests. It uses the
-[`Submit Dispatcher`](/documentation/02-core/dispatcher.mdx) to handle requests and the
-[`Cache`](/documentation/02-core/cache.mdx) to manage the overall state of the data.
-
-The minimum requirement for `useSubmit` is a prepared [`Request`](/documentation/02-core/request.mdx).
-
-If you intend to `retrieve` data from the server, we recommend choosing the
-[`useFetch`](/documentation/04-react/02-core/use-fetch.mdx) hook.
-
----
-
-## Initialization
-
-```tsx
-const { submit, submitting, onSubmitSuccess, onSubmitError, onSubmitFinished } = useSubmit(postLogin);
-```
-
----
-
-## How it works?
-
-**`useSubmit`** executes a request when a `submit()` function returned from it gets triggered. It uses dependency
-tracking to limit re-rendering and improve performance. Under the hood, communication with the core systems is
-established by event emitters. Many `"helper hooks"` (such as `onSubmitSuccess`, `onSubmitError`, `onSubmitFinished`,
-etc.) are returned; these will help handle the request flow and lifecycle. This approach avoids overloading the base
-hook with callback logic. It also helps improve code readability, decreases code complication, and promotes more
-organized code.
-
-```tsx
-import { useSubmit } from "@hyper-fetch/react";
-import { postLogin } from "server";
-
-interface Values {
- email: string;
- password: string;
-}
-
-const LoginPage: React.FC = () => {
- const { submit, submitting, onSubmitSuccess, onSubmitError, onSubmitFinished } = useSubmit(postLogin);
-
- onSubmitSuccess(({ response }) => {
- console.log(response); // { token: string, refreshToken: string }
- });
-
- onSubmitError(({ response }) => {
- console.log(response); // { message: string }
- });
-
- onSubmitFinished(({ response }) => {
- const [payload, error, status] = response;
- console.log(payload); // { token: string, refreshToken: string } | null
- console.log(error); // { message: string } | null
- console.log(status); // 200 / 400 / 404 / 500 ...
- });
-
- const onSubmit = (values: Values) => {
- submit({ data: values });
- };
-
- return (
-
-
-
- );
-};
-```
-
----
-
-## Passing data and params
-
-Data and parameters can be passed in several ways. One option is to use methods on the
-[`Request`](/documentation/02-core/request.mdx), such as `setData` or `setParams`.
-
-```tsx
-const { submit } = useSubmit(patchUser.setParams({ userId: 1 }).setData({ name: "New Name" }));
-```
-
-However, you may need to pass parameters dynamically, which requires using `submit` function options.
-
-```tsx
-const { submit } = useSubmit(patchUser);
-
-const handleSubmit = (id: number, name: string) => {
- submit({ data: { name }, params: { userId: id }, queryParams: { search: "test" } });
-};
-```
-
----
-
-## Options
-
-These configuration options should be provided as a second parameter:
-
-```tsx
-const { ... } = useSubmit(request, options)
-```
-
-{@import React UseSubmitOptionsType returns}
-
----
-
-## Returns
-
-Returned values from this hook:
-
-```tsx
-const values = useSubmit(request);
-```
-
-{@import React useSubmit returns}
diff --git a/documentation/docs/documentation/04-react/03-sockets/use-emitter.mdx b/documentation/docs/documentation/04-react/03-sockets/use-emitter.mdx
deleted file mode 100644
index 6db05daae..000000000
--- a/documentation/docs/documentation/04-react/03-sockets/use-emitter.mdx
+++ /dev/null
@@ -1,152 +0,0 @@
----
-sidebar_position: 4
-title: Sockets emitter
-sidebar_label: useEmitter
----
-
-# useEmitter
-
-
-
useEmitter
-
-
-[Read the API Reference »](/api/React/Hook/useEmitter.mdx)
-
-
-
-
----
-
-## Introduction
-
-This hook **send events** to the server. The minimum requirement for `useEmitter` is a prepared
-[`Emitter`](/documentation/03-sockets/emitter.mdx).
-
-If you intend to `listen` to events from the server, we recommend choosing the
-[`useListener`](/documentation/04-react/03-sockets/use-listener.mdx) hook.
-
----
-
-## Initialization
-
-```tsx
-const { emit, timestamp, connected, onEvent, onError, onReconnecting } = useEmitter(postLogin);
-```
-
----
-
-## How it works?
-
-**`useEmitter`** executes a Emitter when a `emit()` function returned from it gets triggered. It uses dependency
-tracking to limit re-rendering and improve performance. Under the hood, communication with the core systems is
-established by event emitters. Many `"helper hooks"` (such as `onEvent`, `onError`, `onReconnecting`, etc.) are
-returned; these will help handle the request flow and lifecycle. This approach avoids overloading the base hook with
-callback logic. It also helps improve code readability, decreases code complication, and promotes more organized code.
-
-```tsx
-import { socketInstance } from "./socket";
-
-export const emitMessage = socketInstance.createEmitter()({
- endpoint: "chat-message", // endpoint of the event
-});
-```
-
-#### Use it in your component.
-
-```tsx
-import { useEmitter } from "@hyper-fetch/react";
-import { emitMessage } from "./api";
-
-const MessageComponent: React.FC = () => {
- const { emit, timestamp, connected, onEvent, onError, onReconnecting } = useEmitter(postLogin);
-
- onEvent((emitter) => {
- // Event before we send event message
- console.log(emitter); // Emitter instance
- });
-
- onError((error) => {
- console.log(error); // Error Event
- });
-
- onReconnecting((reconnectingAttempt) => {
- console.log(reconnectingAttempt); // 1
- });
-
- const onSubmit = (values: Values) => {
- // ResponseDataType is automatically inherited from Emitter class
- const acknowledge = (error: Error, data: ResponseDataType) => {
- if (error) {
- alert("No server response!");
- } else {
- alert("Message received on server.");
- }
- };
-
- emit({ data: values }, acknowledge);
- };
-
- return (
-
-
-
- );
-};
-```
-
----
-
-## Passing data and params
-
-Data and parameters can be passed in several ways. One option is to use `setData` method on the
-[`Emitter`](/documentation/03-sockets/emitter.mdx).
-
-```tsx
-const { emit } = useEmitter(emitMessage.setData({ message: "New message" }));
-```
-
-However, you may need to pass parameters dynamically, which requires using `emit` function options.
-
-```tsx
-const { emit } = useEmitter(emitMessage);
-
-const handleSubmit = (id: number, name: string) => {
- // ResponseDataType is automatically inherited from Emitter class
- emit({ data: { name } }, (error: Error, data: ResponseDataType) => {
- if (error) {
- alert("No server response!");
- } else {
- alert("Message received on server.");
- }
- });
-};
-```
-
----
-
-## Options
-
-These configuration options should be provided as a second parameter:
-
-```tsx
-const { ... } = useEmitter(emitter, options)
-```
-
-{@import React UseEmitterOptionsType returns}
-
----
-
-## Returns
-
-Returned values from this hook:
-
-```tsx
-const values = useEmitter(emitter);
-```
-
-{@import React useEmitter returns}
diff --git a/documentation/docs/documentation/04-react/03-sockets/use-event-messages.mdx b/documentation/docs/documentation/04-react/03-sockets/use-event-messages.mdx
deleted file mode 100644
index 1c4adbcad..000000000
--- a/documentation/docs/documentation/04-react/03-sockets/use-event-messages.mdx
+++ /dev/null
@@ -1,105 +0,0 @@
----
-sidebar_position: 3
-title: Sockets event messages
-sidebar_label: useEventMessages
----
-
-# useEventMessages
-
-
-
useEventMessages
-
-
-[Read the API Reference »](/api/React/Hook/useEventMessages.mdx)
-
-
-
-
----
-
-## Introduction
-
-This hook is created to **listen to ALL events** received from the server.
-
-If you intend to `send` events to the server, we recommend choosing the
-[`useEmitter`](/documentation/04-react/03-sockets/use-emitter.mdx) hook.
-
----
-
-## Initialization
-
-```tsx
-const { data, timestamp, connected, connecting, onEvent, onError, onReconnecting } = useEventMessages(onChatMessage);
-```
-
----
-
-## How it works?
-
-**`useEventMessages`** hooks into Socket adapter and start listening to given event when a component is mounted. It uses
-dependency tracking to limit re-rendering and help with performance.
-
-Under the hood, communication with the core systems is established by event emitters. There are many `"helper hooks"`
-that get returned from the hook, like `onEvent`, `onError`, and `onReconnecting` (among others). They will help you
-handle various events in the lifecycle of sockets communication.
-
-We used this approach to avoid overloading the base hook with callback logic, which causes low code readability and
-increases complexity.
-
-```tsx
-import { useEventMessages } from "@hyper-fetch/react";
-import { onChatMessage } from "server";
-
-const UsersListPage: React.FC = () => {
- const [messages, setMessages] = useState([])
- const { data, connected, connecting, onEvent, onError, onReconnecting } = useEventMessages(onChatMessage);
-
- onEvent(({ data: message }) => {
- setMessages((prev) => [...prev, message]); // [ MessageType, MessageType, MessageType ]
- });
-
- onError((error) => {
- console.log(error); // Error Event
- });
-
- onReconnecting((reconnectingAttempt) => {
- console.log(reconnectingAttempt); // 1
- })
-
- if(error && !connecting) {
- return {error.message}
- }
-
- return (
-
- {connecting &&
}
- {!messages.length && No messages
}
- {!messages.length && {messages.map(message =>
{message}
)}
}
-
- );
-};
-```
-
----
-
-## Options
-
-Configuration options for `useEventMessages` must be provided as the second parameter.
-
-```tsx
-const { ... } = useEventMessages(listener, options)
-```
-
-{@import React UseEventMessagesOptionsType returns}
-
----
-
-## Returns
-
-Returned values from this hook.
-
-```tsx
-const values = useEventMessages(listener);
-```
-
-{@import React useEventMessages returns}
diff --git a/documentation/docs/documentation/04-react/03-sockets/use-listener.mdx b/documentation/docs/documentation/04-react/03-sockets/use-listener.mdx
deleted file mode 100644
index 5a0aad041..000000000
--- a/documentation/docs/documentation/04-react/03-sockets/use-listener.mdx
+++ /dev/null
@@ -1,115 +0,0 @@
----
-sidebar_position: 3
-title: Sockets listener
-sidebar_label: useListener
----
-
-# useListener
-
-
-
useListener
-
-
-[Read the API Reference »](/api/React/Hook/useListener.mdx)
-
-
-
-
----
-
-## Introduction
-
-This hook is created to **listen to events** received from the server.
-
-If you intend to `send` events to the server, we recommend choosing the
-[`useEmitter`](/documentation/04-react/03-sockets/use-emitter.mdx) hook.
-
----
-
-## Initialization
-
-```tsx
-const { data, timestamp, connected, connecting, onEvent, onError, onReconnecting } = useListener(onChatMessage);
-```
-
----
-
-## How it works?
-
-**`useListener`** hooks into Socket adapter and start listening to given event when a component is mounted. It uses
-dependency tracking to limit re-rendering and help with performance.
-
-Under the hood, communication with the core systems is established by event emitters. There are many `"helper hooks"`
-that get returned from the hook, like `onEvent`, `onError`, and `onReconnecting` (among others). They will help you
-handle various events in the lifecycle of sockets communication.
-
-We used this approach to avoid overloading the base hook with callback logic, which causes low code readability and
-increases complexity.
-
-```tsx
-import { socketInstance } from "./socket";
-
-export const onChatMessage = socketInstance.createListener()({
- endpoint: "chat-message", // endpoint of the event
-});
-```
-
-#### Use it in your component.
-
-```tsx
-import { useListener } from "@hyper-fetch/react";
-import { onChatMessage } from "server";
-
-const UsersListPage: React.FC = () => {
- const [messages, setMessages] = useState([])
- const { data, connected, connecting, onEvent, onError, onReconnecting } = useListener(onChatMessage);
-
- onEvent(({ data: message }) => {
- setMessages((prev) => [...prev, message]); // [ MessageType, MessageType, MessageType ]
- });
-
- onError((error) => {
- console.log(error); // Error Event
- });
-
- onReconnecting((reconnectingAttempt) => {
- console.log(reconnectingAttempt); // 1
- })
-
- if(error && !connecting) {
- return {error.message}
- }
-
- return (
-
- {connecting &&
}
- {!messages.length && No messages
}
- {!messages.length && {messages.map(message =>
{message}
)}
}
-
- );
-};
-```
-
----
-
-## Options
-
-Configuration options for `useListener` must be provided as the second parameter.
-
-```tsx
-const { ... } = useListener(listener, options)
-```
-
-{@import React UseListenerOptionsType returns}
-
----
-
-## Returns
-
-Returned values from this hook.
-
-```tsx
-const values = useListener(listener);
-```
-
-{@import React useListener returns}
diff --git a/documentation/docs/documentation/05-adapters/01-overview.mdx b/documentation/docs/documentation/05-adapters/01-overview.mdx
deleted file mode 100644
index 66e837e4c..000000000
--- a/documentation/docs/documentation/05-adapters/01-overview.mdx
+++ /dev/null
@@ -1,13 +0,0 @@
----
-sidebar_position: 1
-title: Adapters
-sidebar_label: Overview
----
-
----
-
-## About
-
-Adapter is a package wrapping another existing package or framework, enhancing it with all the HF features, and
-enhancing HF with all the possibilities of the adapted package. Writing an adapter is easy as HF allows for easy extension of `BaseAdapterType` and
-our prepared set of methods called *adapter bindings*.
diff --git a/documentation/docs/documentation/05-adapters/_category_.json b/documentation/docs/documentation/05-adapters/_category_.json
deleted file mode 100644
index 8f184fda8..000000000
--- a/documentation/docs/documentation/05-adapters/_category_.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "label": "Adapters"
-}
diff --git a/documentation/docs/documentation/05-adapters/axios/01-introduction.mdx b/documentation/docs/documentation/05-adapters/axios/01-introduction.mdx
deleted file mode 100644
index 6d78fc81e..000000000
--- a/documentation/docs/documentation/05-adapters/axios/01-introduction.mdx
+++ /dev/null
@@ -1,36 +0,0 @@
----
-sidebar_position: 1
-title: Axios introduction
-sidebar_label: Introduction
----
-
-Hyper Fetch `axios` adapter is a simple integration that allows Hyper Fetch users to utilize a lot of features
-of the `axios` library along with all the features available in Hyper Fetch.
-
-## Getting Started
-
-In order to set `axios` adapter, you have to import it from the `@hyper-fetch/axios` package:
-
-```tsx
-import { Client } from "@hyper-fetch/core";
-import { axiosAdapter } from "@hyper-fetch/axios";
-
-const client = new Client({ url: "base-url" }).setAdapter(axiosAdapter);
-```
-
-...and voila! It's done. Now you can set all the axios options, either during the request initialization or via
-`setOptions` method:
-
-```tsx
-const client = new Client({ url: "base-url" }).setAdapter(axiosAdapter);
-const request = client.createRequest()({
- endpoint: "/shared-endpoint",
- options: {} // here
-});
-
-const requestWithOptions = request.setOptions({}) // or here
-```
-
-## Differences
-
-1. You should not pass the `baseUrl`, `method`, and `url` in the axios options. They will be overwritten by the Hyper Fetch adapter.
diff --git a/documentation/docs/documentation/05-adapters/firebase/01-introduction.mdx b/documentation/docs/documentation/05-adapters/firebase/01-introduction.mdx
deleted file mode 100644
index d689a9a92..000000000
--- a/documentation/docs/documentation/05-adapters/firebase/01-introduction.mdx
+++ /dev/null
@@ -1,91 +0,0 @@
----
-sidebar_position: 1
-title: Firebase introduction
-sidebar_label: Introduction
----
-
-Hyper Fetch `firebase` packages offer complete integration of `realtime database` and `firestore`, both for frontend and
-backend, with a single, unified approach for all of them.
-
-## Getting Started
-
-In order to start using the firebase adapter, you have to initialize the firestore/realtime database and set the correct
-adapter on the `client`.
-
-There are two packages to chose from with two adapters each:
-
-1. `@hyper-fetch/firebase` - for working with web realtime and firestore databases:
- 1. `firebaseAdapter` - for standard REST requests.
- 2. `firebaseSocketsAdapter` - for realtime listening.
-2. `@hyper-fetch/firebase-admin` - for admin versions of the packages:
- 1. `firebaseAdminAdapter` - for standard REST requests.
- 2. `firebaseSocketsAdminAdapter` - for realtime listening.
-
-Both packages have the same unified interface.
-
-```tsx
-import { firebaseAdapter } from "@hyper-fetch/firebase";
-import { initializeApp } from "firebase/app";
-import { getFirestore } from "firebase/firestore";
-
-// Firebase firestore database initialization
-const app = initializeApp({
- projectId: "demo-test-firestore",
-});
-const db = getFirestore(app);
-
-// Setting up the HyperFetch with a firebase adapter
-const client = new Client({ url: "teas/" }).setAdapter(() => firebaseAdapter(db));
-const getReq = client.createRequest()({
- endpoint: "",
- method: "getDocs",
-});
-
-// Checking the results
-const { data, status, extra, success, error } = await getReq.send();
-```
-
-In case of firebase admin, the only difference is the import:
-
-```tsx
-import { firebaseAdminAdapter } from "@hyper-fetch/firebase-admin";
-...
-```
-
-Resulting `response` is an object that contains the following properties:
-
-1. `data` - data returned from the database. Each object returned from the database is enhanced also by the `__key` param that equals id of a given document.
-2. `status` - status indicating whether a request ended with `success`, `error` or `emptyResource`. `emptyResource`
- occurs when the request to firebase succeeded but no data was returned.
-3. `success` - general information if overall request succeeded (`true`) or failed (`false`)
-4. `error` - contains error object if the request failed.
-5. `extra` - contains additional properties, depending on a method used. For instance, for `getDocs` method - it allows
- to access `ref` and `snapshot` from firestore firebase.
-
-## Differences from 'raw' firebase
-
-1. If we store an array in firebase, for instance `[a, b, c]`, the query would return the same array. However, if the
- array stops being sequential - for instance, if `a` and `b` were deleted, firebase would return and object: {2: 'c',
- 4: 'e'}. Hyper Fetch always returns and array. Each object in an array has an additional `__key` property, that indicates the id of a given object.
-
-## Filtering queries
-
-In order to standardize the interface across both admin/web firestore/realtime, the filtering and limiting queries is
-done via setting the `constraints` queryParam:
-
-```tsx
-import { $limit, $orderBy, $where } from "constraints";
-
-const req = client.createRequest()({
- endpoint: "",
- method: "getDocs",
-}); // or via setQueryParams method
-const { data } = await req.send({
- queryParams: { constraints: [$where("type", "==", "Green"), $orderBy("year"), $limit(1)] },
-});
-```
-
-User can pass the array of constrains and filters. Please pay attention to the fact that you need to filter via method
-wrappers provided via `adapter-firebase` package: `$where`, `$orderBy`, `$limit`, `$startAt`, `$startAfter`, `$endAt`,
-`$endAfter`, `$orderByChild`, `$orderByKey`, `$orderByValue`, `$limitToFirst`, `$limitToLast`, `$equalTo`. All of these
-methods work exactly the same as their corresponding firebase equivalents.
diff --git a/documentation/docs/documentation/05-adapters/firebase/02-firestore.mdx b/documentation/docs/documentation/05-adapters/firebase/02-firestore.mdx
deleted file mode 100644
index 1cf1c8e6f..000000000
--- a/documentation/docs/documentation/05-adapters/firebase/02-firestore.mdx
+++ /dev/null
@@ -1,105 +0,0 @@
----
-sidebar_position: 2
-title: Working with Firestore
-sidebar_label: Firestore
----
-
-## Available methods
-
-After setting the firestore adapter, we can start performing requests! We should select the appropriate method, corresponding with
-firebase methods. If you want to learn more about available methods - please refer to the firebase documentation.
-
-Due to its nature, we've solved the realtime listening a bit differently, and thus - this method is not allowed in a standard adapter.
-For the `onSnapshot`-like usage, please check how to **[listen to queries](/docs/documentation/adapters/firebase/realtime-queries)**.
-
-```tsx
-const getReq = client.createRequest()({
- endpoint: "",
- method: "getDocs", // "addDoc" | "getDoc" | "getDocs" | "setDoc" | "updateDoc" | "deleteDoc"
-});
-
-```
-
-### getDocs
-
-```tsx
-const getReq = client.createRequest()({
- endpoint: "",
- method: "getDocs",
-});
-
-const { data, status, extra, success, error } = await req.send();
-// Data is an array of objects, each object also contains the __key param.
-```
-
-`extra`:
-1. `ref` - collection reference endpoint
-2. `snapshot` - 'raw' `getDocs` firestore collection/query reference snapshot
-
-### getDoc
-
-```tsx
- const req = client
- .createRequest()({
- endpoint: ":teaId",
- method: "getDoc",
- })
- .setParams({ teaId: 1 });
-
-const { data, status, extra, success, error } = await req.send();
- // setParams can be also passed in the send() method instead
-```
-
-`extra`:
-1. `ref` - document reference endpoint
-2. `snapshot` - 'raw' firestore document reference snapshot
-
-### setDoc
-
-```tsx
-const newData = { origin: "Poland", type: "Green", year: 2023, name: "Pou Ran Do Cha", amount: 10 }
-const setReq = client
- .createRequest()({
- endpoint: ":teaId",
- method: "setDoc",
- // can also pass options: {merge: true} for achieving the firebase 'merge' option
- })
- .setParams({ teaId: 1 })
- .setData(newData);
-
-await setReq.send();
-const { data } = await getReq.send();
-```
-
-In case of `setDoc` - data returned is the same data as passed for setting.
-
-### addDoc
-
-```tsx
-const addDocReq = client
- .createRequest()({
- endpoint: "",
- method: "addDoc",
- options: {},
- })
- .setData(newData);
-
-await addDocReq.send()
-```
-
-In case of `addDoc` - data returned is the same as passed data for setting + the `__key` param that is id of a newly created document.
-
-### deleteDoc
-
-```tsx
-const deleteDocReq = client
- .createRequest()({
- endpoint: ":teaId",
- method: "deleteDoc",
- })
- .setParams({ teaId: 1 });
-
-await deleteDocReq
-```
-
-In case of `deleteDoc` - returned data equals `null`
diff --git a/documentation/docs/documentation/05-adapters/firebase/03-realtime.mdx b/documentation/docs/documentation/05-adapters/firebase/03-realtime.mdx
deleted file mode 100644
index 2251aa70e..000000000
--- a/documentation/docs/documentation/05-adapters/firebase/03-realtime.mdx
+++ /dev/null
@@ -1,104 +0,0 @@
----
-sidebar_position: 3
-title: Working with Realtime database
-sidebar_label: Realtime Database
----
-
-## Available methods
-
-Our Realtime Database adapter provides all the methods the original offers. Due to its nature, we've solved the realtime listening a bit differently, and thus - this method is not allowed in standard adapter.
-For the `onValue`-like usage, please check how to **[listen to queries](/docs/documentation/adapters/firebase/realtime-queries)**.
-
-### get
-
-```tsx
-import {firebaseAdapter} from "@hyper-fetch/firebase";
-
-const client = new Client({ url: "teas/" }).setAdapter(() => firebaseAdapter(realtimeDbWeb));
- const req = client.createRequest()({
- endpoint: "",
- method: "get",
- });
-
-const { data, status, extra, success, error } = await req.send();
-```
-
-`extra`:
-1. `ref` - reference to the endpoint
-2. `snapshot` - 'raw' snapshot from the result
-
-### set
-
-```tsx
-const setReq = client
- .createRequest()({
- endpoint: ":teaId",
- method: "set",
- })
- .setParams({ teaId: 1 })
- .setData(newData);
-
-const { data, status, extra, success, error } = await req.send();
-```
-
-In case of `set` - data returned is the same data as passed for setting.
-
-`extra`:
-1. ref - database reference to the path
-
-You can also **remove data** via set by sending the `{data: null}` object:
-```tsx
-const setReq = client.createRequest()({
- endpoint: ":teaId",
- method: "set",
-})
-.setParams({ teaId: 1 })
-.setData({data: null});
-```
-
-### push
-
-```tsx
-const pushReq = client
- .createRequest()({
- endpoint: "",
- method: "push",
- options: {},
- })
- .setData(newData);
-```
-
-In case of `push` - data returned is the same data as passed for setting + the `__key` param that equals id of a newly created document.
-
-`extra`:
-1. ref - database reference to the path
-2. key - key of the newly created resource
-
-### update
-
-```tsx
-const updateReq = client
- .createRequest()({
- endpoint: ":teaId",
- method: "update",
- })
- .setData(newData);
-```
-
-In case of `update` - data returned is the same data as passed for setting.
-
-`extra`:
-1. ref - database reference to the path
-
-### remove
-
-```tsx
-const removeReq = client
- .createRequest()({
- endpoint: ":teaId",
- method: "remove",
- })
- .setParams({ teaId: 1 });
-```
-
-In case of `remove` - returned data equals `null`
diff --git a/documentation/docs/documentation/05-adapters/graphql/01-introduction.mdx b/documentation/docs/documentation/05-adapters/graphql/01-introduction.mdx
deleted file mode 100644
index b407e4488..000000000
--- a/documentation/docs/documentation/05-adapters/graphql/01-introduction.mdx
+++ /dev/null
@@ -1,34 +0,0 @@
----
-sidebar_position: 1
-title: Graphql introduction
-sidebar_label: Introduction
----
-
-Hyper Fetch GraphQL is a powerful adapter designed to seamlessly handle GraphQL requests in both server and browser
-environments. Built with efficiency and ease-of-use in mind, to simplify process of integration.
-
-## Getting Started
-
-Whether you're developing a server-side GraphQL API or a client-side application that consumes GraphQL data, you can use
-Hyper Fetch GraphQL to interact with it. Process of setting up the adapter is very simple and straightforward.
-
-```tsx
-import { graphqlAdapter } from "@hyper-fetch/graphql";
-
-// Initialize Client with adapter
-const client = new Client({ url: "http://localhost:3000/grahql" }).setAdapter(graphqlAdapter);
-
-// It's ready to use!
-const getUser = client.createRequest()({
- endpoint: gql`
- query GetUser {
- username {
- username
- firstName
- }
- }
- `,
-});
-
-const { data, status, extra, success, error } = await getUser.send();
-```
diff --git a/documentation/docs/documentation/05-adapters/graphql/02-queries.mdx b/documentation/docs/documentation/05-adapters/graphql/02-queries.mdx
deleted file mode 100644
index d1cda72f2..000000000
--- a/documentation/docs/documentation/05-adapters/graphql/02-queries.mdx
+++ /dev/null
@@ -1,58 +0,0 @@
----
-sidebar_position: 1
-title: Working with queries
-sidebar_label: Queries
----
-
-To make queries, follow these simple steps after ensuring you have the necessary prerequisites in place: a query schema
-and a client set up with our GraphQL adapter.
-
-## Getting Started
-
-```tsx
-import { graphqlAdapter } from "@hyper-fetch/graphql";
-
-// Initialize Client with adapter
-const client = new Client({ url: "http://localhost:3000/grahql" }).setAdapter(graphqlAdapter);
-
-// It's ready to use!
-const getUser = client.createRequest()({
- endpoint: gql`
- query GetUser {
- username {
- username
- firstName
- }
- }
- `,
-});
-
-const { data, status, extra, success, error } = await getUser.send();
-```
-
-## Typescript
-
-Depending on your schema and preferences, you can enhance the query process by incorporating types.
-
-```tsx
-type User = {
- username: string;
- firstName: string;
-};
-type Variables = {
- filter: string;
-};
-
-const getUser = client.createRequest()({
- endpoint: gql`
- query GetUser {
- username(filter: $filter) {
- username
- firstName
- }
- }
- `,
-});
-
-const { data, status, extra, success, error } = await getUser.setData({ filter: "Some filter" }).send();
-```
diff --git a/documentation/docs/documentation/05-adapters/graphql/03-mutations.mdx b/documentation/docs/documentation/05-adapters/graphql/03-mutations.mdx
deleted file mode 100644
index 98a7385ee..000000000
--- a/documentation/docs/documentation/05-adapters/graphql/03-mutations.mdx
+++ /dev/null
@@ -1,40 +0,0 @@
----
-sidebar_position: 1
-title: Working with mutations
-sidebar_label: Mutations
----
-
-To make mutations you need a query schema and a client set up with our GraphQL adapter.
-
-## Getting Started
-
-```tsx
-import { graphqlAdapter } from "@hyper-fetch/graphql";
-
-// Initialize Client with adapter
-const client = new Client({ url: "http://localhost:3000/grahql" }).setAdapter(graphqlAdapter);
-
-type Variables = {
- username: string;
- password: string;
-};
-
-// It's ready to use!
-const login = client.createRequest()({
- endpoint: gql`
- mutation Login($username: String!, $password: String!) {
- login(username: $username, password: $password) {
- username
- password
- }
- }
- `,
-});
-
-const { data, status, extra, success, error } = await getUser
- .setData({
- username: "Some username",
- password: "Some password",
- })
- .send();
-```
diff --git a/documentation/docs/documentation/05-adapters/graphql/04-graphql-tag.mdx b/documentation/docs/documentation/05-adapters/graphql/04-graphql-tag.mdx
deleted file mode 100644
index 76fb43a38..000000000
--- a/documentation/docs/documentation/05-adapters/graphql/04-graphql-tag.mdx
+++ /dev/null
@@ -1,24 +0,0 @@
----
-sidebar_position: 2
-title: Using graphql-tag
-sidebar_label: Graphql-tag
----
-
-## graphql-tag
-
-You can use tagging libraries, as we use the graphql `print` method to make sure the query is transformed to a string.
-
-```ts
-const getUser = client.createRequest()({
- endpoint: gql`
- query GetUser {
- username {
- username
- firstName
- }
- }
- `,
-});
-
-const { data, status, extra, success, error } = await getUser.send();
-```
diff --git a/documentation/docs/documentation/06-generators/01-overview.mdx b/documentation/docs/documentation/06-generators/01-overview.mdx
deleted file mode 100644
index 0162105f1..000000000
--- a/documentation/docs/documentation/06-generators/01-overview.mdx
+++ /dev/null
@@ -1,11 +0,0 @@
----
-sidebar_position: 1
-title: Code Generators
-sidebar_label: Overview
----
-
----
-
-## About
-
-Code generators are used to facilitate the life of a developer and save development time.
diff --git a/documentation/docs/documentation/06-generators/_category_.json b/documentation/docs/documentation/06-generators/_category_.json
deleted file mode 100644
index 733e38f3f..000000000
--- a/documentation/docs/documentation/06-generators/_category_.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "label": "Code Generators"
-}
diff --git a/documentation/docs/documentation/06-generators/openapi/01-introduction.mdx b/documentation/docs/documentation/06-generators/openapi/01-introduction.mdx
deleted file mode 100644
index a8861b1b8..000000000
--- a/documentation/docs/documentation/06-generators/openapi/01-introduction.mdx
+++ /dev/null
@@ -1,92 +0,0 @@
----
-sidebar_position: 1
-title: Openapi generator introduction
-sidebar_label: Introduction
----
-
-:::info
-
-Openapi Hyper Fetch code generator is in beta. Please let us know in case of any problems.
-
-:::
-
-:::info
-
-Note: Right now this code generator accepts only V3 version of the openapi schema.
-
-:::
-
-
-## Getting Started
-
-In order to start using the request generator, you need only one thing: OpenApi V3 JSON schema file or link to it. Then,
-you can simply call the package via `npx`:
-
-```tsx
-npx @hyper-fetch/codegen-openapi --schema https://petstore3.swagger.io/api/v3/openapi.json
-```
-
-This command will generate the `openapi.client.ts` that contains generated Hyper Fetch client, requests, and types:
-
-```tsx
-...
-export const client = new Client({ url: "/api/v3" });
-
-...
-export type UpdatePetRequestBody = Paths.UpdatePet.RequestBody;
-export type UpdatePetResponseType = Paths.UpdatePet.Responses.$200;
-
-export type AddPetRequestBody = Paths.AddPet.RequestBody;
-export type AddPetResponseType = Paths.AddPet.Responses.$200;
-
-...
-
-export const updatePet = client.createRequest()({
- method: "PUT",
- endpoint: "/pet",
-});
-
-export const addPet = client.createRequest()({
- method: "POST",
- endpoint: "/pet",
-});
-
-```
-
-Declared variables with a created request always take their name from camel-cased `operationId`.
-The types naming always follows the convention - pascalCased `operationId` + {`ResponseType`/`RequestBody`/`QueryParams`}, e.g.:
-
-- operationId: `addPet`
-- declared variable: `addPet`
-- response type: `AddPetResponseType`
-- request body: `AddPetRequestBody`
-
-## Renaming the file
-
-The command also accepts a second, optional argument: `--name`, that allows to indicate the name of a resulting file:
-
-```tsx
-npx @hyper-fetch/codegen-openapi --schema https://petstore3.swagger.io/api/v3/openapi.json --name hyper-fetch.requests.ts
-```
-
-## Providing base url
-
-By default, we take the base url from the first `server` param from the json schema:
-```json
-{
-"servers": [{ "url": "/api/v3" }]
-}
-```
-
-However, you can provide the `--url` option for the cli that will be used instead:
-
-```tsx
-npx @hyper-fetch/codegen-openapi --schema https://petstore3.swagger.io/api/v3/openapi.json --name hyper-fetch.requests.ts --url https://petstore3.swagger.io
-```
-
-Then, the client from the generated file will use it:
-
-```tsx
-... // generated file
-export const client = new Client({url: "https://petstore3.swagger.io"})
-```
diff --git a/documentation/docs/documentation/01-getting-started/_category_.json b/documentation/docs/getting-started/_category_.json
similarity index 100%
rename from documentation/docs/documentation/01-getting-started/_category_.json
rename to documentation/docs/getting-started/_category_.json
diff --git a/documentation/docs/getting-started/comparison.mdx b/documentation/docs/getting-started/comparison.mdx
new file mode 100644
index 000000000..5b24a1435
--- /dev/null
+++ b/documentation/docs/getting-started/comparison.mdx
@@ -0,0 +1,930 @@
+---
+sidebar_position: 8
+title: Why Hyper Fetch is Unique
+sidebar_label: Comparison
+---
+
+import { Info } from "lucide-react";
+import Tippy from "@tippyjs/react";
+import "tippy.js/dist/tippy.css";
+
+# Comparison
+
+The biggest difference between **`Hyper Fetch`** and other libraries is the opinionated architecture and assumptions on
+which it is built. Hyper Fetch’s core features are written in TS **without dependencies**; because of this, it can work
+in many environments without a specific connection to a given framework.
+
+Hyper Fetch is not just a wrapper; it offers full control over the flow and observation of data exchange. Our main goals
+were to introduce:
+
+- a data storage standard,
+- offer an embedded HTTP adapter,
+- reduce setup times,
+- solve major architectural difficulties.
+
+:::info
+
+Producing an accurate and unbiased comparison is quite a challenge. Libraries develop quickly, so if you notice that our
+data needs to be corrected, please let us know by opening an issue.
+
+:::
+
+---
+
+## Why Hyper Fetch Is Unique
+
+- Easy upload/download progress and ETA tracking
+- Supports request queueing and many [dispatching strategies](/core/dispatcher.mdx#dispatching-modes)!
+- [Command](/core/request.mdx) / [Builder](/core/client.mdx) pattern gives you amazing control over requests at any time
+- Code-sharing architecture lets [testers to hook into development setup and types](/getting-started/testing.mdx)
+- Features flat side-effects [helper hooks annotation](/react/01-overview.mdx#helper-hooks) and promotes readable code
+- Provides structure [recipes](/getting-started/development.mdx#structure) for large scale applications that
+ significantly limit maintenance costs.
+- Core features include [offline](/guides/02-advanced/offline.mdx) and
+ [persistence](/guides/02-advanced/persistence.mdx) support, giving you full control over your data
+
+---
+
+## Features
+
+✅ - Documented support
+🚧 - Work in progress
+🔵 - Require additional Plugin/Coding
+🔴 - Not supported / Not documented
+
+
+
+
+
+
+
+
+
+ Hyper Fetch
+
+
+ Query
+
+
+
+ SWR
+
+
+ Apollo
+
+
+
+
+
+ Supported environments
+ Any
+ Any
+ React
+ Any
+
+
+ Protocols
+ Any
+ Any
+ Any
+ GraphQL
+
+
+ Caching Approach
+ Request Schema
+ Hierarchical Key > Value
+ Unique Key > Value
+ Normalized Schema
+
+
+ Cache Key Strategy
+ Request Key
+ JSON
+ JSON
+ GraphQL Query
+
+
+ Data Change Detection
+ Deep Comparison
+ Deep Comparison
+ Deep Comparison
+ Deep Comparison
+
+
+ Data Memoization
+ Normalized Identity
+ Full Structural Sharing
+ Identity
+ Normalized Identity
+
+
+ Queue Key Strategy
+ Request Key
+ N/A
+ N/A
+ N/A
+
+
+ Devtools
+ ✅
+ ✅
+ 🔵
+ ✅
+
+
+
+
+
+
+ Server Connection Setup
+
+
+
+ ✅
+ 🔵
+ 🔵
+ ✅
+
+
+
+
+
+
+ Shared Request
+
+
+
+ ✅
+ 🔵
+ 🔵
+ ✅
+
+
+
+
+
+
+ Dependency tracking
+
+
+
+ ✅
+ ✅
+ ✅
+ ✅
+
+
+ Cache Persistence
+ ✅
+ ✅
+ ✅
+ ✅
+
+
+
+
+
+
+ Requests Persistence
+
+
+
+ ✅
+ 🔴
+ 🔴
+ 🔴
+
+
+
+
+
+
+ Download ETA
+
+
+
+ ✅
+ 🔵
+ 🔵
+ 🔵
+
+
+
+
+
+
+ Uploading ETA
+
+
+
+ ✅
+ 🔵
+ 🔵
+ 🔵
+
+
+
+
+
+
+ Pooling
+
+
+
+ ✅
+ ✅
+ ✅
+ ✅
+
+
+
+
+
+
+ Dependent Queries
+
+
+
+ ✅
+ ✅
+ ✅
+ ✅
+
+
+ Paginated Queries
+ ✅
+ ✅
+ ✅
+ ✅
+
+
+
+
+
+
+ Query Params Parsing
+
+
+
+ ✅
+ 🔵
+ 🔵
+ 🔵
+
+
+
+
+
+
+ Queueing
+
+
+
+ ✅
+ 🔴
+ 🔴
+ 🔴
+
+
+
+
+
+
+ Retries
+
+
+
+ ✅
+ ✅
+ ✅
+ 🔵
+
+
+
+
+
+
+ Default Adapter
+
+
+
+ ✅
+ 🔴
+ 🔴
+ ✅
+
+
+
+
+
+
+ Infinite Queries
+
+
+
+ ✅
+ ✅
+ ✅
+ ✅
+
+
+
+
+
+
+ SSR
+
+
+
+ ✅
+ ✅
+ ✅
+ ✅
+
+
+
+
+
+
+ Initial Data
+
+
+
+ ✅
+ ✅
+ ✅
+ ✅
+
+
+
+
+
+
+ Cache Hydration
+
+
+
+ ✅
+ ✅
+ 🔴
+ ✅
+
+
+
+
+
+
+ Garbage Collecting
+
+
+
+ ✅
+ ✅
+ 🔴
+ 🔴
+
+
+
+
+
+
+ Pre Request Intercepting
+
+
+
+ ✅
+ 🔵
+ 🔵
+ ✅
+
+
+
+
+
+
+ Post Request Intercepting
+
+
+
+ ✅
+ 🔵
+ 🔵
+ ✅
+
+
+
+
+
+
+ Prefetching
+
+
+
+ ✅
+ ✅
+ 🔵
+ ✅
+
+
+
+
+
+
+ Cancellation
+
+
+
+ ✅
+ ✅
+ 🔴
+ 🔴
+
+
+
+
+
+
+ Queue Cancellation
+
+
+
+ ✅
+ 🔴
+ 🔴
+ 🔴
+
+
+
+
+
+
+ Authentication
+
+
+
+ ✅
+ 🔵
+ 🔵
+ ✅
+
+
+
+
+
+
+ Stale While Revalidate
+
+
+
+ ✅
+ ✅
+ ✅
+ ✅
+
+
+ Refresh Data
+ ✅
+ ✅
+ ✅
+ ✅
+
+
+
+
+
+
+ Offline Request Pause
+
+
+
+ ✅
+ ✅
+ 🔴
+ 🔴
+
+
+
+
+
+
+ Network Status Re-fetching
+
+
+
+ ✅
+ ✅
+ ✅
+ ✅
+
+
+
+
+
+
+ Window Focus Re-fetching
+
+
+
+ ✅
+ ✅
+ ✅
+ 🔴
+
+
+
+
+
+
+ Normalized Caching
+
+
+
+ ✅
+ 🔴
+ 🔴
+ ✅
+
+
+
+
+
+
+ Automatic Re-fetch After Mutation
+
+
+
+ ✅
+ 🔵
+ 🔵
+ ✅
+
+
+
+
+
+
+ Query Matching
+
+
+
+ ✅
+ ✅
+ 🔴
+ 🔴
+
+
+
+
+
+
+ Cache Matching
+
+
+
+ ✅
+ ✅
+ ✅
+ ✅
+
+
+
+
+
+
+ Query Lifecycle Events
+
+
+
+ ✅
+ 🔴
+ 🔴
+ ✅
+
+
+
+
+
+
+ Data Flow Standard
+
+
+
+ ✅
+ 🔴
+ 🔴
+ ✅
+
+
+
+
+
+
+ Request Start/Stop
+
+
+
+ ✅
+ 🔴
+ 🔴
+ 🔴
+
+
+
+
+
+
+ Request Queue Start/Stop/Pause
+
+
+
+ ✅
+ 🔴
+ 🔴
+ 🔴
+
+
+
+
+
+
+ Request Data Mapping
+
+
+
+ ✅
+ 🔵
+ 🔵
+ N/A
+
+
+
+
+
+
+ Cache Invalidation
+
+
+
+ ✅
+ ✅
+ ✅
+ ✅
+
+
+
+
+
+
+ File Uploading
+
+
+
+ ✅
+ 🔵
+ 🔵
+ ✅
+
+
+
+
+
+
+ Global Response Side-Effects
+
+
+
+ ✅
+ 🔴
+ 🔴
+ 🔴
+
+
+
+
+
+
+ Scroll Recovery
+
+
+
+ ✅
+ ✅
+ ✅
+ ✅
+
+
+
+
+
+
+ Simple Request Execution
+
+
+
+ ✅
+ 🔴
+ 🔴
+ 🔴
+
+
+
+
+
+
+ Requests Manager
+
+
+
+ ✅
+ 🔴
+ 🔴
+ 🔴
+
+
+
+
+
+
+ Tabs Storages Synchronization
+
+
+
+ 🚧
+ 🚧
+ 🔴
+ 🔴
+
+
+
+
+
+
+ Tabs Dispatching Synchronization
+
+
+
+ 🚧
+ 🔴
+ 🔴
+ 🔴
+
+
+
+
+
+
+ Websocket
+
+
+
+ ✅
+ 🔴
+ 🔴
+ 🔴
+
+
+
+
+
+
+ Server Sent Events
+
+
+
+ ✅
+ 🔴
+ 🔴
+ 🔴
+
+
+
+
+
+---
+
+## Typescript features
+
+
+
+
+
+
+ Hyper Fetch
+
+
+ Query
+
+
+
+ SWR
+
+
+ Apollo
+
+
+
+
+
+
+
+
+
+ Response types
+
+
+
+ ✅
+ ✅
+ ✅
+ ✅
+
+
+
+
+
+
+ Request data types
+
+
+
+ ✅
+ ✅
+ ✅
+ ✅
+
+
+
+
+
+
+ Global error types
+
+
+
+ ✅
+ 🔴
+ 🔴
+ ✅
+
+
+
+
+
+
+ Local error types
+
+
+
+ ✅
+ 🔴
+ 🔴
+ 🔴
+
+
+
+
+
+
+ Query params types
+
+
+
+ ✅
+ 🔴
+ 🔴
+ ✅
+
+
+
+
+
+
+ Params types
+
+
+
+ ✅
+ 🔴
+ 🔴
+ ✅
+
+
+
+
+
+
+ Request state tracking types
+
+
+
+ ✅
+ 🔴
+ 🔴
+ ✅
+
+
+
+
diff --git a/documentation/docs/getting-started/components/cards.tsx b/documentation/docs/getting-started/components/cards.tsx
new file mode 100644
index 000000000..29cbbbddc
--- /dev/null
+++ b/documentation/docs/getting-started/components/cards.tsx
@@ -0,0 +1,36 @@
+/* eslint-disable react/no-array-index-key */
+import { useSidebar } from "@site/src/hooks/use-sidebar";
+import { Description, Title, Noise, DocsCard } from "@site/src/components";
+
+export const Cards = () => {
+ const { sidebar } = useSidebar();
+
+ return (
+
+ );
+};
diff --git a/documentation/docs/getting-started/components/environments.tsx b/documentation/docs/getting-started/components/environments.tsx
new file mode 100644
index 000000000..fb20acc8d
--- /dev/null
+++ b/documentation/docs/getting-started/components/environments.tsx
@@ -0,0 +1,71 @@
+/* eslint-disable react/no-array-index-key */
+import { Description, Title, Noise, DocsCard } from "@site/src/components";
+import { cn } from "@site/src/lib/utils";
+
+const environments = [
+ {
+ name: "Web & PWA",
+ description: "Fully supported Web and PWA environments.",
+ icon: "✅",
+ },
+ {
+ name: "React",
+ description: "Fully supported React environments with hooks and integrations.",
+ icon: "✅",
+ },
+ {
+ name: "React Native",
+ description: "Fully supported React Native environments with hooks and integrations.",
+ icon: "✅",
+ },
+ {
+ name: "SSR",
+ description: "Fully supported SSR environments (Next.js, Astro, Tanstack Router) with hydration abilities.",
+ icon: "✅",
+ },
+ {
+ name: "Node.js",
+ description: "Supporting Node.js environments with server integrations.",
+ icon: "✅",
+ },
+ {
+ name: "Svelte",
+ description: "Hyper Fetch is working with Svelte, but do not expose any hooks yet.",
+ icon: "⚙️",
+ },
+ {
+ name: "Vue",
+ description: "Hyper Fetch is working with Vue, but do not expose any hooks yet.",
+ icon: "⚙️",
+ },
+];
+export const Environments = () => {
+ return (
+
+ {environments.map((item, index) => {
+ return (
+
+
+
+
+
+ {item.name}
+
+
+ {item.description}
+
+
+
+ );
+ })}
+
+ );
+};
diff --git a/documentation/docs/getting-started/development.mdx b/documentation/docs/getting-started/development.mdx
new file mode 100644
index 000000000..b94806a93
--- /dev/null
+++ b/documentation/docs/getting-started/development.mdx
@@ -0,0 +1,63 @@
+---
+sidebar_position: 4
+title: Development
+sidebar_label: Development
+---
+
+# Development
+
+To help you get started with Hyper Fetch, we've outlined a few best practices for structuring your project. These are
+suggestions, feel free to adapt them to your workflow.
+
+---
+
+## 1. Project Structure
+
+1. **Organize by Feature:** Start by creating an `/api` directory to house your **client** and related **requests**.
+
+2. **Entity-Based Directories:** For each entity in your system (e.g., users, todos, categories, products, groups),
+ create a separate directory within `/api` to store the corresponding requests.
+
+3. **Maximize Reusability:** By leveraging classes and an object-oriented approach, you can easily access and reuse
+ requests throughout your application. This structure also allows your tests to utilize existing configurations
+ without duplication.
+
+**Example Structure:**
+
+```
+src
+│
+├── api
+│ ├── client.ts
+│ ├── users
+│ │ └── users.api.ts
+│ ├── products
+│ │ └── products.api.ts
+│ └── ...
+├── ...
+└── ...
+```
+
+---
+
+## 2. Debugging
+
+Preferred to debug is by using [Hyper Flow](docs/hyper-flow) - dedicated devtools for Hyper Fetch. It allows you to see
+all the requests, responses, and errors in one place - manage cache and see detailed statistics.
+
+
+
+
+
+### Alternatively you can debug apps in one of two ways:
+
+1. **Use the built-in logger**
+
+Use the client `setDebug(true)` method for this. It will start logging actions in the console. To adjust what type of
+logs will be shown, use `setLogLevel(3)` to get debug logs displayed in the console. Those will show you the exact data
+and information flow in the library while working on your application.
+
+2. **Create your own logger**
+
+You can create your own dev tools based on events sent from the [requestManager](/core/managers.mdx#requestmanager).
+There is no limitation, and you can receive all necessary data to create everything you may need.
diff --git a/documentation/docs/getting-started/index.mdx b/documentation/docs/getting-started/index.mdx
new file mode 100644
index 000000000..060679abb
--- /dev/null
+++ b/documentation/docs/getting-started/index.mdx
@@ -0,0 +1,77 @@
+---
+sidebar_position: 1
+title: Getting started
+sidebar_label: Intro
+---
+
+import { Cards } from "./components/cards";
+import { Environments } from "./components/environments";
+
+> **`Hyper Fetch`** is a modern, open source framework for request-based and real-time communication, purpose-built to
+> eliminate boilerplate and streamline data handling across any TypeScript environment—whether you're working in the
+> browser, on the server, or in native platforms like React Native or Electron.
+
+## Modules
+
+Our framework consist of the core modules which are responsible for the request-based and real-time communication or
+connecting to particular framework - like Hyper-Fetch React.
+
+
+
+## Environments
+
+Core library should work in any JavaScript environment.
+
+For frontend frameworks and libraries, we release additional packages that enrich core logic and add appropriate API
+connections for the given environment (as with the addition of hooks in React).
+
+
+
+## Integrations
+
+We also provide integrations for some of the most popular data-exchange libraries or services like Firebase.
+
+
+
+## Our Motivation
+
+We got the idea for Hyper Fetch after leading several React projects. There are many great libraries using for fetching
+data like `Axios`, `SWR`, and `React Query`. However, the logic that they provide is detached from each other – i.e. the
+hooks are detached from the fetchers. So you often need to mix them together in order to fetch the data.
+
+This gives users a lot of customization options, but it also comes with some issues - for example how to track
+upload/download progress, how to call the requests outside of the components while still using the caching and other
+features. It is hard to inform the hooks about the request status inside of the components or SSR environments.
+
+Usually you’d need to build your logic every time you start developing a new application. And there is no
+`standard schema` nor any standards on how to manage this. It usually causes the challenges on the project level in how
+to name things, how to organize requests and of course you have to build the whole logic around it.
+
+We decided to overcome this issue by creating a _straightforward_, _opinionated_, yet _flexible_ fetching solution.
+
+## Our Goals
+
+1. Establish a consistent, neutral standard for seamless data exchange.
+2. Accelerate development by reusing logic and configurations, eliminating repetitive work across projects.
+3. Benefit from a comprehensive set of built-in fetching capabilities, easily extendable to meet custom requirements.
+4. Centralize server configurations to avoid duplication and ensure consistency between and within projects.
+5. Boost development speed: set up fetchers and dependencies in minutes, drastically reducing setup time.
+6. Effortlessly monitor request progress and manage queues with intuitive tracking tools.
+7. Leverage advanced offline support and data persistence features for robust application behavior.
+8. Improve developer experience and code quality through automated processes that prevent common errors.
+
+## Guides
+
+We have many examples and guides to help you get started.
+
+
diff --git a/documentation/docs/getting-started/installation.mdx b/documentation/docs/getting-started/installation.mdx
new file mode 100644
index 000000000..b28ba09ff
--- /dev/null
+++ b/documentation/docs/getting-started/installation.mdx
@@ -0,0 +1,63 @@
+---
+sidebar_position: 3
+title: Installation
+sidebar_label: Installation
+---
+
+An installation of Hyper Fetch can be run `clean` or for a specific environment. However, we only currently support
+React.
+
+:::info
+
+The main `@hyper-fetch/core` package is required for other sub packages to work.
+
+:::
+
+---
+
+## Install Core packages
+
+For minimal installation, you need to install the core package and eslint plugin.
+
+```bash npm2yarn2pnpm
+npm install --save @hyper-fetch/core eslint-plugin-hyper-fetch
+```
+
+:::warning
+
+[Eslint plugin](../integrations/plugin-eslint/) is required for maximum type safety. It enhances the abilities of the
+typescript via checking the object generic types to match exact schema.
+
+:::
+
+---
+
+## Sockets
+
+Sockets is created for handling websockets or server sent events.
+
+```bash npm2yarn2pnpm
+npm install --save @hyper-fetch/sockets
+```
+
+---
+
+## React
+
+React allows the installation of the base library with hooks, offering interfaces that facilitate library usage and
+support the application lifecycle.
+
+```bash npm2yarn2pnpm
+bun add @hyper-fetch/core @hyper-fetch/react
+```
+
+---
+
+## Integrations
+
+
diff --git a/documentation/docs/getting-started/quick-start.mdx b/documentation/docs/getting-started/quick-start.mdx
new file mode 100644
index 000000000..458551ca4
--- /dev/null
+++ b/documentation/docs/getting-started/quick-start.mdx
@@ -0,0 +1,66 @@
+---
+sidebar_position: 2
+title: Quick Start
+sidebar_label: Quick Start
+---
+
+# Quick Start
+
+Welcome to Hyper Fetch! Our library is designed to be modular, so you can choose the packages that best suit your
+project's needs. We offer several Quick Start guides to help you get up and running as smoothly as possible.
+
+---
+
+## Quick Starts
+
+Each guide is tailored to a specific package, providing you with focused instructions and examples to get you started.
+
+### Core
+
+Hyper Fetch's core is framework-agnostic, giving you the power to handle data fetching in any JavaScript environment.
+This guide will walk you through the fundamentals of setting up the client and making your first requests.
+
+
+
+---
+
+### Sockets
+
+Learn how to integrate real-time communication in your application using Hyper Fetch Sockets. This guide covers setting
+up listeners and emitters for seamless, bi-directional data flow with your server.
+
+
+
+---
+
+### React
+
+Unlock the full potential of Hyper Fetch in your React applications. This guide will show you how to use our powerful
+hooks to manage server state with ease, simplifying data fetching, submission, and state management.
+
+
+
+---
+
+## More guides
+
+For more guides, check out the guides page. You will find there guides for each package.
+
+
diff --git a/documentation/docs/guides/01-basic/dispatching.mdx b/documentation/docs/guides/01-basic/dispatching.mdx
deleted file mode 100644
index a7db630b5..000000000
--- a/documentation/docs/guides/01-basic/dispatching.mdx
+++ /dev/null
@@ -1,90 +0,0 @@
----
-sidebar_position: 1
-title: Guide - Dispatching
-sidebar_label: Dispatching
----
-
-# Dispatching
-
----
-
-### Trigger request
-
-We can execute queries using the built-in `send()` function or use React hooks.
-
-```tsx
-import { postLogin } from "server/auth";
-
-...
-
-const handleLogin = async (values: {email: string, password: string}) => {
- const { data, error, status } = await postLogin.setData(values).send();
-
- if(data) {
- // perform login
- ...
- } else {
- // handle error
- ...
- }
-
-}
-
-...
-
-```
-
-### Method `send()`
-
-The send method takes full advantage of the potential of our features. We have implemented `debouncing`, `retries`,
-`cancellation` and `offline awaiting` solutions.
-
-We can also dynamically transfer data to execute the request.
-
-```tsx
-import { postData } from "server/auth";
-
-...
-
-const handleSend = async (values: ValuesType) => {
- const { data, error, status } = await postData.send({
- data: values,
- params: { accountId: 2 },
- queryParams: { param1: "test", param2: [1,2,3] }
- })
-
- if(data) {
- // perform success action
- ...
- } else {
- // handle error
- ...
- }
-
-}
-
-...
-
-```
-
-### Lifecycle
-
-`send()` method allow us to hook into request lifecycle. We can do it with one of following methods.
-
-{@import Hyper-Fetch FetchSendActionsType preview}
-
-#### Example
-
-```ts
-const { data, error, status } = await getData.send({
- onSettle: (requestId) => {
- console.log(`Starting request: ${requestId}`);
- },
- onDownloadProgress: (values) => {
- console.log(`Download progress: ${values}`);
- },
- onResponse: (response) => {
- console.log(`Got response: ${response}`);
- },
-});
-```
diff --git a/documentation/docs/guides/01-basic/global-defaults.mdx b/documentation/docs/guides/01-basic/global-defaults.mdx
deleted file mode 100644
index 22a4161c6..000000000
--- a/documentation/docs/guides/01-basic/global-defaults.mdx
+++ /dev/null
@@ -1,55 +0,0 @@
----
-sidebar_position: 10
-title: Guide - Global Defaults
-sidebar_label: Global Defaults
----
-
-# Global Defaults
-
----
-
-### Use global defaults for request
-
-Adding global configs can significantly limit application setup. For the greatest flexibility in configurations created for larger and more complex applications,
-global configs are added through callbacks based on request data. This allows us the flexibility to, for example,
-make one default configuration for requests using the get method and another default config for the requests using other methods.
-
-Remember: Global configurations are overwritten by request settings, so the options that we set will be applied only to requests that do not have settings specified in their options.
-
----
-
-### Example
-
-```ts
-export const client = new Client({ url }).setRequestDefaultOptions((requestOptions) => {
- if (requestOptions.method === "GET") {
- return {
- deduplicate: true,
- cacheTime: 20000,
- retry: 3,
- };
- }
-
- return {
- deduplicate: false,
- cache: false,
- retry: 0,
- };
-});
-```
-
-### Add your own key mappers
-
-Data and requests made within our library are organized by keys. Each key is generated from request metadata, such as
-parameters, query parameters, endpoints, and methods. They can be replaced by the way you choose to segregate and organize data
-with your own key mappers.
-
-Note: Keys must be a string value.
-
-
-```ts
-client.setQueueKeyMapper((request) => `Custom_Key_${request.method}_${request.endpoint}`);
-client.setAbortKeyMapper((request) => `Abort_Key_${request.method}_${request.endpoint}`);
-client.setCacheKeyMapper((request) => `Abort_Key_${request.method}_${request.endpoint}`);
-client.setEffectKeyMapper((request) => `Abort_Key_${request.method}_${request.endpoint}`);
-```
diff --git a/documentation/docs/guides/01-basic/query-params.mdx b/documentation/docs/guides/01-basic/query-params.mdx
deleted file mode 100644
index 7c6645cd3..000000000
--- a/documentation/docs/guides/01-basic/query-params.mdx
+++ /dev/null
@@ -1,52 +0,0 @@
----
-sidebar_position: 4
-title: Guide - Query Params
-sidebar_label: Query Params
----
-
-# Query Params
-
----
-
-### Request query parameters
-
-The use of query params is based on built-in parser. We can freely change its options and format to match our needs.
-
----
-
-### Setting query params
-
-You can set query params by using the `setQueryParams` method on request. It's type can be configured on request
-creation.
-
-```ts
-type QueryParamsType = {
- search: string;
- sort: string;
-};
-
-const getUsers = client.createRequest()({ endpoint: "/users" });
-
-// Setting the query params
-
-const request = getUsers.setQueryParams({ search: "John", sort: "age" });
-console.log(request.endpoint); // Output: "/users?search=John&sort=age"
-```
-
-```ts
-const getUsers = client.createRequest()({ endpoint: "/users" });
-
-const request = getUsers.setQueryParams("search=John&sort=age");
-console.log(request.endpoint); // Output: "/users?search=John&sort=age"
-```
-
-### Custom query params format
-
-We can setup custom config with instructions how to stringify the values. It can be setup on the client with
-`setQueryParamsConfig` method.
-
-#### Available options:
-
-{@import Hyper-Fetch QueryStringifyOptionsType returns}
-
----
diff --git a/documentation/docs/guides/01-basic/setup.mdx b/documentation/docs/guides/01-basic/setup.mdx
deleted file mode 100644
index da50e3787..000000000
--- a/documentation/docs/guides/01-basic/setup.mdx
+++ /dev/null
@@ -1,60 +0,0 @@
----
-sidebar_position: 0
-title: Guides - Setup
-sidebar_label: Setup
----
-
-# Setup
-
----
-
-### Initialize Client
-
-The first step is to initialize the **[Client](/documentation/02-core/client.mdx)**. It manage the basic configuration
-for connection to the server and all the elements that make up Hyper Fetch, which are instances of - **dispatchers**,
-**cache** and **app managers**. We start by determining the `url` of our server.
-
-```tsx title="/src/server/client.ts"
-import { Client } from "@hyper-fetch/core";
-
-export const client = new Client({ url: "http://localhost:3000" });
-```
-
-### Create Request
-
-Then, having already prepared connection setup for the server, we use the client method to create
-**[requests](/documentation/02-core/request.mdx)** and assign types to them.
-
-:::caution
-
-We are using currying to achieve auto generated types for the endpoint string. This solution will be removed once
-[https://github.com/microsoft/TypeScript/issues/10571](https://github.com/microsoft/TypeScript/issues/10571) get
-resolved.
-
-:::
-
-```tsx title="/src/server/auth/auth.ts"
-import { client } from "../client.ts";
-
-type ResponseType = { token: string; refreshToken: string };
-type RequestType = { email: string; password: string };
-
-const postLogin = client.createRequest()({ method: "POST", endpoint: "/auth/login" });
-```
-
-## Simple Requests
-
-```ts
-const getRepositoryDetails = client.createRequest()({
- method: "GET",
- url: "/repos/BetterTyped/hyper-fetch",
-});
-
-const { data, error, status, extra } = await getRepositoryDetails.send();
-
-const { data, error, status, extra } = await postLogin.send({
- data: { email: "test@test.com", password: "Password123$" }, // Please, do not use this password ;)
-});
-```
-
-## Congratulations! You're ready to use **Hyper Fetch**! 🎊
diff --git a/documentation/docs/guides/03-sockets/setup.mdx b/documentation/docs/guides/03-sockets/setup.mdx
deleted file mode 100644
index e259a8704..000000000
--- a/documentation/docs/guides/03-sockets/setup.mdx
+++ /dev/null
@@ -1,59 +0,0 @@
----
-sidebar_position: 1
-title: Socket Setup Guide
-sidebar_label: Setup
----
-
-# Setup
-
----
-
-### Initialize Socket
-
-The first step is to initialize the **[Socket](/documentation/03-sockets/socket.mdx)**. It manage the basic
-configuration for connection to the server and all the sub-systems. We start by determining the `url` of our server.
-
-```tsx title="/src/server/socket.ts"
-import { Socket } from "@hyper-fetch/sockets";
-
-export const socket = new Socket({ url: "ws://localhost:3000" });
-```
-
-### Create Listener
-
-Then, having already prepared connection setup for the server, we use the socket method to create
-**[Listeners](/documentation/03-sockets/listener.mdx)** and assign types to them.
-
-```tsx
-type ChatMessageType = {
- message: string;
-};
-
-export const onChatMessage = socketInstance.createListener()({
- endpoint: "chat-message", // endpoint of the event
-});
-```
-
-### Create Emitter
-
-Then, having already prepared connection setup for the server, we use the socket method to create
-**[Emitter](/documentation/03-sockets/emitter.mdx)** and assign types to them.
-
-```tsx
-import { socketInstance } from "./socket";
-
-type ChatMessageType = {
- message: string;
-};
-
-// Optional
-type AcknowledgementResponseType = {
- value: string;
-};
-
-export const sendChatMessage = socketInstance.createEmitter()({
- endpoint: "chat-message", // endpoint of the event
-});
-```
-
-## You're ready to use Hyper Fetch Sockets! 🎊
diff --git a/documentation/docs/guides/01-basic/_category_.json b/documentation/docs/guides/core/01-basics/_category_.json
similarity index 100%
rename from documentation/docs/guides/01-basic/_category_.json
rename to documentation/docs/guides/core/01-basics/_category_.json
diff --git a/documentation/versioned_docs/version-4.x.x/guides/01-basic/authentication.mdx b/documentation/docs/guides/core/01-basics/authentication.mdx
similarity index 86%
rename from documentation/versioned_docs/version-4.x.x/guides/01-basic/authentication.mdx
rename to documentation/docs/guides/core/01-basics/authentication.mdx
index 3651ec200..cd7acf117 100644
--- a/documentation/versioned_docs/version-4.x.x/guides/01-basic/authentication.mdx
+++ b/documentation/docs/guides/core/01-basics/authentication.mdx
@@ -6,8 +6,8 @@ sidebar_label: Authentication
# Authentication
-Authentication in Hyper Fetch consists of two steps. We will introduce changes in the
-**[Client](/documentation/02-core/client.mdx)** instance and subsequent requests created from it.
+Authentication in Hyper Fetch consists of two steps. We will introduce changes in the **[Client](/core/client.mdx)**
+instance and subsequent requests created from it.
---
@@ -43,8 +43,8 @@ That's it, from now on, each request made using this request will be authenticat
### Refresh token
-To refresh the token, we can add a special `onError` interceptor to our **[Client](/documentation/02-core/client.mdx)**.
-It intercepts errors received in our requests and it is asynchronous, which allows for efficient handling of such cases.
+To refresh the token, we can add a special `onError` interceptor to our **[Client](/core/client.mdx)**. It intercepts
+errors received in our requests and it is asynchronous, which allows for efficient handling of such cases.
To properly **`avoid the infinite refresh loop`** of the token, we need to protect ourselves by setting the `used` field
to **true** thanks to the appropriate method `setUsed`. This will allow us to easily verify whether our commend has
@@ -61,7 +61,7 @@ export const client = new Client({ url }).onError(async (response, request) => {
// not go into infinite loop and trigger this operation only once
if (!request.used && refreshToken && status === 401) {
// Prepare the refresh token request
- const postRefreshToken = client.createRequest()({
+ const postRefreshToken = client.createRequest<{ response: LoginResponse; payload: LoginData }>()({
endpoint: "/refresh-token",
method: "POST",
});
diff --git a/documentation/docs/guides/01-basic/data-mapping.mdx b/documentation/docs/guides/core/01-basics/data-mapping.mdx
similarity index 75%
rename from documentation/docs/guides/01-basic/data-mapping.mdx
rename to documentation/docs/guides/core/01-basics/data-mapping.mdx
index d492c23bd..770c66729 100644
--- a/documentation/docs/guides/01-basic/data-mapping.mdx
+++ b/documentation/docs/guides/core/01-basics/data-mapping.mdx
@@ -12,12 +12,13 @@ sidebar_label: Data Mapping
We often encounter the need to `map` data before sending it to the server. This is usually required for two reasons.
-One of them is `breaking changes to the server API`. This may require many updates to our existing code,
-which can be dangerous for the application and introduce **regression**.
+One of them is `breaking changes to the server API`. This may require many updates to our existing code, which can be
+dangerous for the application and introduce **regression**.
Another case is sending `FormData`, which is impossible to represent in the form of an exact interface in terms of the
fields it contains. In order not to send something that is equivalent to the type `any`, we can specify the correct type
-in the request and then map everything to `FormData` just before it gets added to the **[Dispatcher](/documentation/02-core/dispatcher.mdx)**.
+in the request and then map everything to `FormData` just before it gets added to the
+**[Dispatcher](/core/dispatcher.mdx)**.
This ensures very `type-safe` and `flexible` application development.
@@ -27,7 +28,7 @@ The following example shows the implementation for `FormData`:
```ts
export const postUserProfile = client
- .createRequest()({
+ .createRequest<{ response: boolean; payload: UserProfile }>()({
method: "PATCH",
endpoint: "/users/profile/:userId",
})
@@ -47,13 +48,13 @@ export const postUserProfile = client
### Map whole request
The example below shows the implementation of request mapping. We can make each `postUserProfile` request add custom
-headers (or any other value) to the request before sending it later (when we use it in our application).
-This allows us to implement mappers, validators, and any async logic. Throwing an error makes the request class return an error,
-just as we’d get from the "real" query.
+headers (or any other value) to the request before sending it later (when we use it in our application). This allows us
+to implement mappers, validators, and any async logic. Throwing an error makes the request class return an error, just
+as we’d get from the "real" query.
```ts
export const postUserProfile = client
- .createRequest()({
+ .createRequest<{ response: boolean; payload: UserProfile }>()({
method: "PATCH",
endpoint: "/users/profile/:userId",
})
diff --git a/documentation/docs/guides/core/01-basics/dispatching.mdx b/documentation/docs/guides/core/01-basics/dispatching.mdx
new file mode 100644
index 000000000..077f531c0
--- /dev/null
+++ b/documentation/docs/guides/core/01-basics/dispatching.mdx
@@ -0,0 +1,90 @@
+---
+sidebar_position: 1
+title: Guide - Dispatching
+sidebar_label: Dispatching
+---
+
+# Dispatching
+
+---
+
+### Trigger request
+
+We can execute queries using the built-in `send()` function or use React hooks.
+
+```tsx
+import { postLogin } from "server/auth";
+
+...
+
+const handleLogin = async (values: {email: string, password: string}) => {
+ const { data, error, status } = await postLogin.setData(values).send();
+
+ if(data) {
+ // perform login
+ ...
+ } else {
+ // handle error
+ ...
+ }
+
+}
+
+...
+
+```
+
+### Method `send()`
+
+The send method takes full advantage of the potential of our features. We have implemented `debouncing`, `retries`,
+`cancellation` and `offline awaiting` solutions.
+
+We can also dynamically transfer data to execute the request.
+
+```tsx
+import { postData } from "server/auth";
+
+...
+
+const handleSend = async (values: ValuesType) => {
+ const { data, error, status } = await postData.send({
+ data: values,
+ params: { accountId: 2 },
+ queryParams: { param1: "test", param2: [1,2,3] }
+ })
+
+ if(data) {
+ // perform success action
+ ...
+ } else {
+ // handle error
+ ...
+ }
+
+}
+
+...
+
+```
+
+### Lifecycle
+
+`send()` method allow us to hook into request lifecycle. We can do it with one of following methods.
+
+(@import core RequestSendType type=preview)
+
+#### Example
+
+```ts
+const { data, error, status } = await getData.send({
+ onBeforeSent: (requestId) => {
+ console.log(`Starting request: ${requestId}`);
+ },
+ onDownloadProgress: (values) => {
+ console.log(`Download progress: ${values}`);
+ },
+ onResponse: (response) => {
+ console.log(`Got response: ${response}`);
+ },
+});
+```
diff --git a/documentation/versioned_docs/version-4.x.x/guides/01-basic/error-handling.mdx b/documentation/docs/guides/core/01-basics/error-handling.mdx
similarity index 89%
rename from documentation/versioned_docs/version-4.x.x/guides/01-basic/error-handling.mdx
rename to documentation/docs/guides/core/01-basics/error-handling.mdx
index 3e6fe363d..14c19ab80 100644
--- a/documentation/versioned_docs/version-4.x.x/guides/01-basic/error-handling.mdx
+++ b/documentation/docs/guides/core/01-basics/error-handling.mdx
@@ -31,7 +31,7 @@ type GlobalErrorType = {
status: 400 | 404 | 500;
};
-export const client = new Client({ url });
+export const client = new Client<{error: GlobalErrorType} >({ url });
```
Now the error type of our request will reflect `GlobalErrorType`.
@@ -60,7 +60,7 @@ type LocalErrorType = {
};
};
-const postUser = client.createRequest()({
+const postUser = client.createRequest<{response: ResponseType, payload: RequestType, localError: LocalErrorType}>()({
method: "POST",
endpoint: "/users",
});
diff --git a/documentation/docs/guides/core/01-basics/global-defaults.mdx b/documentation/docs/guides/core/01-basics/global-defaults.mdx
new file mode 100644
index 000000000..ddc8ee2df
--- /dev/null
+++ b/documentation/docs/guides/core/01-basics/global-defaults.mdx
@@ -0,0 +1,62 @@
+---
+sidebar_position: 10
+title: Guide - Global Defaults
+sidebar_label: Global Defaults
+---
+
+{/* setRequestDefaults */}
+
+{/* setAdapterDefaults */}
+
+{/* keys generation */}
+
+# Global Defaults
+
+---
+
+### Use global defaults for request
+
+Adding global configs can significantly limit application setup. For the greatest flexibility in configurations created
+for larger and more complex applications, global configs are added through callbacks based on request data. This allows
+us the flexibility to, for example, make one default configuration for requests using the get method and another default
+config for the requests using other methods.
+
+Remember: Global configurations are overwritten by request settings, so the options that we set will be applied only to
+requests that do not have settings specified in their options.
+
+---
+
+### Example
+
+```ts
+export const client = new Client({ url }).setRequestDefaultOptions((requestOptions) => {
+ if (requestOptions.method === "GET") {
+ return {
+ deduplicate: true,
+ staleTime: 20000,
+ retry: 3,
+ };
+ }
+
+ return {
+ deduplicate: false,
+ cache: false,
+ retry: 0,
+ };
+});
+```
+
+### Add your own key mappers
+
+Data and requests made within our library are organized by keys. Each key is generated from request metadata, such as
+parameters, query parameters, endpoints, and methods. They can be replaced by the way you choose to segregate and
+organize data with your own key mappers.
+
+Note: Keys must be a string value.
+
+```ts
+client.setQueryKeyMapper((request) => `Custom_Key_${request.method}_${request.endpoint}`);
+client.setAbortKeyMapper((request) => `Abort_Key_${request.method}_${request.endpoint}`);
+client.setCacheKeyMapper((request) => `Abort_Key_${request.method}_${request.endpoint}`);
+client.setEffectKeyMapper((request) => `Abort_Key_${request.method}_${request.endpoint}`);
+```
diff --git a/documentation/docs/guides/01-basic/headers.mdx b/documentation/docs/guides/core/01-basics/headers.mdx
similarity index 100%
rename from documentation/docs/guides/01-basic/headers.mdx
rename to documentation/docs/guides/core/01-basics/headers.mdx
diff --git a/documentation/docs/guides/01-basic/parameters.mdx b/documentation/docs/guides/core/01-basics/parameters.mdx
similarity index 100%
rename from documentation/docs/guides/01-basic/parameters.mdx
rename to documentation/docs/guides/core/01-basics/parameters.mdx
diff --git a/documentation/versioned_docs/version-4.x.x/guides/01-basic/payload.mdx b/documentation/docs/guides/core/01-basics/payload.mdx
similarity index 82%
rename from documentation/versioned_docs/version-4.x.x/guides/01-basic/payload.mdx
rename to documentation/docs/guides/core/01-basics/payload.mdx
index 200e29cb2..87e1e867c 100644
--- a/documentation/versioned_docs/version-4.x.x/guides/01-basic/payload.mdx
+++ b/documentation/docs/guides/core/01-basics/payload.mdx
@@ -20,7 +20,7 @@ transfer.
To set data of our request we need to use method `.setData()`.
```ts
-const createUser = client.createRequest()({ method: "POST", endpoint: "/users" });
+const createUser = client.createRequest<{response: ResponseType, payload: DataType}>()({ method: "POST", endpoint: "/users" });
const request = createUser.setData({ name: "Maciej" }); // Must match `DataType`
console.log(request.data); // Output: { name: "Maciej" }
diff --git a/documentation/docs/guides/core/01-basics/query-params.mdx b/documentation/docs/guides/core/01-basics/query-params.mdx
new file mode 100644
index 000000000..d74d236f3
--- /dev/null
+++ b/documentation/docs/guides/core/01-basics/query-params.mdx
@@ -0,0 +1,52 @@
+---
+sidebar_position: 4
+title: Guide - Query Params
+sidebar_label: Query Params
+---
+
+# Query Params
+
+---
+
+### Request query parameters
+
+The use of query params is based on built-in parser. We can freely change its options and format to match our needs.
+
+---
+
+### Setting query params
+
+You can set query params by using the `setQueryParams` method on request. It's type can be configured on request
+creation.
+
+```ts
+type QueryParamsType = {
+ search: string;
+ sort: string;
+};
+
+const getUsers = client.createRequest<{ response: Response; queryParams: QueryParamsType }>()({ endpoint: "/users" });
+
+// Setting the query params
+
+const request = getUsers.setQueryParams({ search: "John", sort: "age" });
+console.log(request.endpoint); // Output: "/users?search=John&sort=age"
+```
+
+```ts
+const getUsers = client.createRequest<{ response: Response; queryParams: string }>()({ endpoint: "/users" });
+
+const request = getUsers.setQueryParams("search=John&sort=age");
+console.log(request.endpoint); // Output: "/users?search=John&sort=age"
+```
+
+### Custom query params format
+
+We can setup custom config with instructions how to stringify the values. It can be setup on the client with
+`setQueryParamsConfig` method.
+
+#### Available options:
+
+(@import core QueryStringifyOptionsType type=returns)
+
+---
diff --git a/documentation/docs/guides/core/01-basics/request.mdx b/documentation/docs/guides/core/01-basics/request.mdx
new file mode 100644
index 000000000..418455dc0
--- /dev/null
+++ b/documentation/docs/guides/core/01-basics/request.mdx
@@ -0,0 +1,9 @@
+---
+sidebar_position: 9
+title: Guide - Create Request
+sidebar_label: Create Request
+---
+
+# Create Request
+
+---
diff --git a/documentation/docs/guides/01-basic/retries.mdx b/documentation/docs/guides/core/01-basics/retries.mdx
similarity index 100%
rename from documentation/docs/guides/01-basic/retries.mdx
rename to documentation/docs/guides/core/01-basics/retries.mdx
diff --git a/documentation/docs/guides/core/01-basics/setup.mdx b/documentation/docs/guides/core/01-basics/setup.mdx
new file mode 100644
index 000000000..72f018c48
--- /dev/null
+++ b/documentation/docs/guides/core/01-basics/setup.mdx
@@ -0,0 +1,81 @@
+---
+sidebar_position: 0
+title: Guides - Setup
+sidebar_label: Setup
+---
+
+:::secondary You'll learn
+
+- How to initialize the Client
+- How to create a Request
+- How to send a Request
+- How to handle the Response
+- How to handle the Error
+- How to handle the Loading
+- How to handle the Cache
+
+:::
+
+{/* show different types for setup */}
+
+{/* show what are the options params */}
+
+{/* move requests creation to the next section */}
+
+{/* show some options with examples */}
+
+---
+
+### Initialize Client
+
+The first step is to initialize the **[Client](/core/client.mdx)**. It manage the basic configuration for connection to
+the server and all the elements that make up Hyper Fetch, which are instances of - **dispatchers**, **cache** and **app
+managers**. We start by determining the `url` of our server.
+
+```tsx title="/src/server/client.ts"
+import { Client } from "@hyper-fetch/core";
+
+export const client = new Client({ url: "http://localhost:3000" });
+```
+
+### Create Request
+
+Then, having already prepared connection setup for the server, we use the client method to create
+**[requests](/core/request.mdx)** and assign types to them.
+
+:::caution
+
+We are using currying to achieve auto generated types for the endpoint string. This solution will be removed once
+[https://github.com/microsoft/TypeScript/issues/10571](https://github.com/microsoft/TypeScript/issues/10571) get
+resolved.
+
+:::
+
+```tsx title="/src/server/auth/auth.ts"
+import { client } from "../client.ts";
+
+type ResponseType = { token: string; refreshToken: string };
+type RequestType = { email: string; password: string };
+
+const postLogin = client.createRequest<{ response: ResponseType; payload: RequestType }>()({
+ method: "POST",
+ endpoint: "/auth/login",
+});
+```
+
+## Simple Requests
+
+```ts
+const getRepositoryDetails = client.createRequest()({
+ method: "GET",
+ url: "/repos/BetterTyped/hyper-fetch",
+});
+
+const { data, error, status, extra } = await getRepositoryDetails.send();
+
+const { data, error, status, extra } = await postLogin.send({
+ data: { email: "test@test.com", password: "Password123$" }, // Please, do not use this password ;)
+});
+```
+
+## Congratulations! You're ready to use **Hyper Fetch**! 🎊
diff --git a/documentation/docs/guides/02-advanced/_category_.json b/documentation/docs/guides/core/02-advanced/_category_.json
similarity index 100%
rename from documentation/docs/guides/02-advanced/_category_.json
rename to documentation/docs/guides/core/02-advanced/_category_.json
diff --git a/documentation/versioned_docs/version-4.x.x/guides/02-advanced/cache-revalidation.mdx b/documentation/docs/guides/core/02-advanced/cache-revalidation.mdx
similarity index 95%
rename from documentation/versioned_docs/version-4.x.x/guides/02-advanced/cache-revalidation.mdx
rename to documentation/docs/guides/core/02-advanced/cache-revalidation.mdx
index eb92490ae..8b32a24eb 100644
--- a/documentation/versioned_docs/version-4.x.x/guides/02-advanced/cache-revalidation.mdx
+++ b/documentation/docs/guides/core/02-advanced/cache-revalidation.mdx
@@ -5,9 +5,6 @@ sidebar_label: Cache Revalidation
# Cache Revalidation
-import Tabs from "@theme/Tabs";
-import TabItem from "@theme/TabItem";
-
When using the application, `we often encounter the need to revalidate data`. This is because of various
`dynamic changes` in the case of the users interacting with our applications. For example, when deleting a note from the
list of notes in the database, we want the already stored data to be refreshed. In this case, we use cache revalidation.
diff --git a/documentation/versioned_docs/version-4.x.x/guides/02-advanced/cancellation.mdx b/documentation/docs/guides/core/02-advanced/cancellation.mdx
similarity index 87%
rename from documentation/versioned_docs/version-4.x.x/guides/02-advanced/cancellation.mdx
rename to documentation/docs/guides/core/02-advanced/cancellation.mdx
index 8d7161b6a..fda332448 100644
--- a/documentation/versioned_docs/version-4.x.x/guides/02-advanced/cancellation.mdx
+++ b/documentation/docs/guides/core/02-advanced/cancellation.mdx
@@ -6,9 +6,6 @@ sidebar_label: Cancellation
# Request Cancellation
-import Tabs from "@theme/Tabs";
-import TabItem from "@theme/TabItem";
-
---
Canceling requests is needed for various reasons. There are cases when we make the request and we want to abort it
@@ -23,7 +20,7 @@ the new one and cancel previous at the same time to prevent `race-conditioning`
we need to set the `cancelable: true` field to request options.
```ts
-const getUsers = client.createRequest()({ endpoint: "/users", cancelable: true });
+const getUsers = client.createRequest<{response: UsersList}>()({ endpoint: "/users", cancelable: true });
// Make a request to server
getUsers.send()
@@ -85,10 +82,10 @@ postFile.send()
// Stop the request from being send for later
// Do not delete it from storage to trigger it later
-client.fetchDispatcher.stop(postFile.queueKey)
+client.fetchDispatcher.stop(postFile.queryKey)
...
// Start sending again
-client.fetchDispatcher.start(postFile.queueKey)
+client.fetchDispatcher.start(postFile.queryKey)
```
diff --git a/documentation/docs/guides/02-advanced/custom-adapter.mdx b/documentation/docs/guides/core/02-advanced/custom-adapter.mdx
similarity index 96%
rename from documentation/docs/guides/02-advanced/custom-adapter.mdx
rename to documentation/docs/guides/core/02-advanced/custom-adapter.mdx
index 508224179..9c8e43508 100644
--- a/documentation/docs/guides/02-advanced/custom-adapter.mdx
+++ b/documentation/docs/guides/core/02-advanced/custom-adapter.mdx
@@ -107,7 +107,7 @@ const customHttpAdapter: BaseAdapterType<
QueryParamsType
> = (request: RequestInstance) => Promise.resolve({ data: null, error: null, status: 0 });
-const client = new Client({ url }).setAdapter(customHttpAdapter);
+const client = new Client<{error: Error}>({ url }).setAdapter(customHttpAdapter);
```
#### Adapter Unions
@@ -124,7 +124,7 @@ type MyAdapter =
const customHttpAdapter: MyAdapter = (request: RequestInstance) =>
Promise.resolve({ data: null, error: null, status: 0 });
-const client = new Client({ url }).setAdapter(customHttpAdapter);
+const client = new Client<{error: Error}>({ url }).setAdapter(customHttpAdapter);
// We decide which type to used based on passed config
diff --git a/documentation/versioned_docs/version-4.x.x/guides/02-advanced/deduplication.mdx b/documentation/docs/guides/core/02-advanced/deduplication.mdx
similarity index 92%
rename from documentation/versioned_docs/version-4.x.x/guides/02-advanced/deduplication.mdx
rename to documentation/docs/guides/core/02-advanced/deduplication.mdx
index a91a0cb93..64e2bea9a 100644
--- a/documentation/versioned_docs/version-4.x.x/guides/02-advanced/deduplication.mdx
+++ b/documentation/docs/guides/core/02-advanced/deduplication.mdx
@@ -36,4 +36,4 @@ getUsers.send();
```
To learn more of `deduplication` and `alternative modes` of requesting you can visit
-**[Dispatcher Docs](/documentation/02-core/dispatcher.mdx#dispatching-modes)**.
+**[Dispatcher Docs](/core/dispatcher.mdx#dispatching-modes)**.
diff --git a/documentation/docs/guides/02-advanced/intercepting.mdx b/documentation/docs/guides/core/02-advanced/intercepting.mdx
similarity index 100%
rename from documentation/docs/guides/02-advanced/intercepting.mdx
rename to documentation/docs/guides/core/02-advanced/intercepting.mdx
diff --git a/documentation/docs/guides/02-advanced/mapping.mdx b/documentation/docs/guides/core/02-advanced/mapping.mdx
similarity index 94%
rename from documentation/docs/guides/02-advanced/mapping.mdx
rename to documentation/docs/guides/core/02-advanced/mapping.mdx
index a49ebb78f..f06d63fdc 100644
--- a/documentation/docs/guides/02-advanced/mapping.mdx
+++ b/documentation/docs/guides/core/02-advanced/mapping.mdx
@@ -22,7 +22,7 @@ Mappers can be asynchronus. This way we can build up bigger responses.
```ts
export const getUser = client
- .createRequest()({
+ .createRequest<{response: UserModel}>()({
method: "GET",
endpoint: "/users/:userId",
})
@@ -49,7 +49,7 @@ For example, the User class can parse dates from an ISO string into a Date objec
```ts
export const getUser = client
- .createRequest()({
+ .createRequest<{response: UserModel}>()({
method: "GET",
endpoint: "/users/:userId",
})
@@ -77,7 +77,7 @@ Mappers can be asynchronous. This lets us build up bigger responses.
```ts
export const postUser = client
- .createRequest()({
+ .createRequest<{response: UserModel, payload: UserData}>()({
method: "POST",
endpoint: "/users/:userId",
})
diff --git a/documentation/versioned_docs/version-4.x.x/guides/02-advanced/offline.mdx b/documentation/docs/guides/core/02-advanced/offline.mdx
similarity index 82%
rename from documentation/versioned_docs/version-4.x.x/guides/02-advanced/offline.mdx
rename to documentation/docs/guides/core/02-advanced/offline.mdx
index 9756e7941..8b5e80eca 100644
--- a/documentation/versioned_docs/version-4.x.x/guides/02-advanced/offline.mdx
+++ b/documentation/docs/guides/core/02-advanced/offline.mdx
@@ -12,9 +12,9 @@ Currently, the operation of this system is default, which means that the offline
automated. Receiving the information that the application has entered the offline state, we automatically stop the
requests being executed or queued, and then resume them when the connection is restored.
-The offline operation is greatly influenced by one of the managers -
-**[AppManager](/api/Hyper-Fetch/Class/AppManager.mdx)**, which is responsible for emitting events related to the current
-state of the application - such as offline / online or focused / blurred.
+The offline operation is greatly influenced by one of the managers - **[AppManager](/api/core/Classes/AppManager.mdx)**,
+which is responsible for emitting events related to the current state of the application - such as offline / online or
+focused / blurred.
---
@@ -25,7 +25,7 @@ online state are based on the window event listeners, when we are talking about
NetInfo as the source of the connection state.
```ts
-export const client = new Client({
+export const client = new Client<{error: ServerErrorType}>({
url: environment.serverUrl,
appManager: (instance) =>
new AppManager(instance, {
diff --git a/documentation/versioned_docs/version-4.x.x/guides/02-advanced/persistence.mdx b/documentation/docs/guides/core/02-advanced/persistence.mdx
similarity index 93%
rename from documentation/versioned_docs/version-4.x.x/guides/02-advanced/persistence.mdx
rename to documentation/docs/guides/core/02-advanced/persistence.mdx
index 161f456d1..5b3dcd9bc 100644
--- a/documentation/versioned_docs/version-4.x.x/guides/02-advanced/persistence.mdx
+++ b/documentation/docs/guides/core/02-advanced/persistence.mdx
@@ -37,7 +37,7 @@ const persistenceStorage: CacheStorageType = {
clear: () => storage.clearAll(),
};
-export const client = new Client({
+export const client = new Client<{ error: ServerErrorType }>({
url: "localhost:3000",
cache: (instance) =>
new Cache(instance, {
@@ -52,7 +52,7 @@ Example below shows the **`IndexedDb`** persistence storage. This way we will us
it to our components. Every time we use the `cache.get(cacheKey)` method, we send a request to our `lazyStorage` and at
the same time return the last data we have, when our promise responds, we will receive an appropriate event that will
propagate the data in our components. This way we are NOT loading whole persistent data into our memory, but only part
-of it, not to mention that it will get garbage collected when it's cacheTime expire.
+of it, not to mention that it will get garbage collected when it's staleTime expire.
```ts
import { get, set, del, keys } from "idb-keyval";
@@ -64,7 +64,7 @@ const asyncStorage: CacheAsyncStorageType = {
delete: (key) => del(key),
};
-export const client = new Client({
+export const client = new Client<{ error: ServerErrorType }>({
url: "localhost:3000",
cache: (instance) =>
new Cache(instance, {
@@ -107,7 +107,7 @@ const persistenceStorage: DispatcherStorageType = {
clear: () => storage.clearAll(),
};
-export const client = new Client({
+export const client = new Client<{ error: ServerErrorType }>({
url: "localhost:3000",
fetchDispatcher: (instance) =>
new Dispatcher(instance, {
@@ -134,7 +134,7 @@ const persistenceStorage: DispatcherStorageType = {
clear: () => storage.clearAll(),
};
-export const client = new Client({
+export const client = new Client<{ error: ServerErrorType }>({
url: "localhost:3000",
submitDispatcher: (instance) =>
new Dispatcher(instance, {
diff --git a/documentation/docs/guides/02-advanced/prefetching.mdx b/documentation/docs/guides/core/02-advanced/prefetching.mdx
similarity index 100%
rename from documentation/docs/guides/02-advanced/prefetching.mdx
rename to documentation/docs/guides/core/02-advanced/prefetching.mdx
diff --git a/documentation/docs/guides/02-advanced/queueing.mdx b/documentation/docs/guides/core/02-advanced/queueing.mdx
similarity index 100%
rename from documentation/docs/guides/02-advanced/queueing.mdx
rename to documentation/docs/guides/core/02-advanced/queueing.mdx
diff --git a/documentation/docs/guides/02-advanced/validation.mdx b/documentation/docs/guides/core/02-advanced/validation.mdx
similarity index 96%
rename from documentation/docs/guides/02-advanced/validation.mdx
rename to documentation/docs/guides/core/02-advanced/validation.mdx
index b1931199c..98be7ad5d 100644
--- a/documentation/docs/guides/02-advanced/validation.mdx
+++ b/documentation/docs/guides/core/02-advanced/validation.mdx
@@ -53,7 +53,7 @@ const User = z.object({
});
export const postUser = client
- .createRequest()({
+ .createRequest<{response: UserModel, payload: UserData}>()({
method: "POST",
endpoint: "/users/:userId",
})
diff --git a/documentation/versioned_docs/version-3.x.x/documentation/01-getting-started/_category_.json b/documentation/docs/guides/getting-started/_category_.json
similarity index 100%
rename from documentation/versioned_docs/version-3.x.x/documentation/01-getting-started/_category_.json
rename to documentation/docs/guides/getting-started/_category_.json
diff --git a/documentation/docs/guides/getting-started/additional-resources.mdx b/documentation/docs/guides/getting-started/additional-resources.mdx
new file mode 100644
index 000000000..dbd9b3f29
--- /dev/null
+++ b/documentation/docs/guides/getting-started/additional-resources.mdx
@@ -0,0 +1,17 @@
+---
+sidebar_position: 3
+title: Additional Resources
+sidebar_label: Additional Resources
+---
+
+Expanding your knowledge about data fetching is essential for building robust web applications. Below are some highly
+recommended resources to help you understand the fundamentals and best practices:
+
+- [MDN Web Docs: Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API)
+ - Comprehensive guide to the Fetch API, including usage examples, browser compatibility, and advanced features.
+- [MDN Web Docs: XMLHttpRequest](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest)
+ - Legacy API reference for XMLHttpRequest, useful for understanding older codebases.
+- [JavaScript.info: Fetch](https://javascript.info/fetch)
+ - In-depth tutorial on using the Fetch API with practical examples and explanations.
+
+> _Tip: Always refer to the official documentation for the most up-to-date and accurate information._
diff --git a/documentation/docs/guides/getting-started/community.mdx b/documentation/docs/guides/getting-started/community.mdx
new file mode 100644
index 000000000..3f9ceb0b4
--- /dev/null
+++ b/documentation/docs/guides/getting-started/community.mdx
@@ -0,0 +1,29 @@
+---
+sidebar_position: 2
+title: Community
+sidebar_label: Community
+---
+
+We welcome and encourage the community to contribute courses, tutorials, and learning resources! If you have created or
+found a valuable course, please add it here to help others learn and grow.
+
+> **No community courses have been added yet.**
+>
+> _Be the first to contribute a course!_
+
+---
+
+## Community Resources
+
+Below is a list of community-created resources, such as blog posts, videos, and guides. If you have a resource to share,
+please add it to the list!
+
+- _No resources have been added yet._
+- _You can add your blog post, video, or guide here!_
+
+---
+
+### How to Contribute
+
+Want to help the community? Add your course or resource by editing this page and submitting a pull request. We
+appreciate your contributions and look forward to seeing this list grow!
diff --git a/documentation/docs/guides/getting-started/index.mdx b/documentation/docs/guides/getting-started/index.mdx
new file mode 100644
index 000000000..67bccfaa3
--- /dev/null
+++ b/documentation/docs/guides/getting-started/index.mdx
@@ -0,0 +1,55 @@
+---
+sidebar_position: 1
+title: Overview
+sidebar_label: Overview
+---
+
+# Guides Overview
+
+> Welcome to the **Hyper Fetch Guides**! This section is your go-to resource for mastering Hyper Fetch through
+> practical, problem-focused tutorials. Whether you're setting up your first request or building complex, real-time
+> features, our guides provide step-by-step instructions and real-world examples to help you succeed.
+
+:::secondary What you'll learn
+
+- How to set up and configure Hyper Fetch for your project
+- Core concepts like creating requests, handling authentication, and managing state
+- Advanced techniques including caching, offline support, and real-time communication with sockets
+- Best practices for integrating Hyper Fetch with React
+- Effective testing strategies for your Hyper Fetch applications
+
+:::
+
+---
+
+## Guides
+
+Our guides are designed to be problem-focused, offering detailed explanations and complete code examples. They provide
+step-by-step instructions for implementing various features, from basic setup to advanced use cases. We aim to provide
+comprehensive guides for each core package, covering everything you need to build robust applications.
+
+---
+
+## Integrations
+
+Our integration guides are located alongside their respective documentation. This approach ensures that all the
+information you need, from setup to advanced usage, is available in one convenient place. This helps you quickly
+understand the nuances of each integration and get started with minimal friction.
+
+
+
+---
+
+:::tip Pro Tip
+
+If you're new, start with the **Getting Started** guide. For specific problems or advanced features, feel free to jump
+directly to the relevant section.
+
+Explore the guides to level up your Hyper Fetch skills and build robust, scalable applications with confidence!
+
+:::
diff --git a/documentation/docs/documentation/04-react/02-core/_category_.json b/documentation/docs/guides/react/01-basics/_category_.json
similarity index 100%
rename from documentation/docs/documentation/04-react/02-core/_category_.json
rename to documentation/docs/guides/react/01-basics/_category_.json
diff --git a/documentation/docs/guides/04-react/01-core/config-provider.mdx b/documentation/docs/guides/react/01-basics/config-provider.mdx
similarity index 100%
rename from documentation/docs/guides/04-react/01-core/config-provider.mdx
rename to documentation/docs/guides/react/01-basics/config-provider.mdx
diff --git a/documentation/docs/guides/04-react/01-core/dependent-requests.mdx b/documentation/docs/guides/react/01-basics/dependent-requests.mdx
similarity index 100%
rename from documentation/docs/guides/04-react/01-core/dependent-requests.mdx
rename to documentation/docs/guides/react/01-basics/dependent-requests.mdx
diff --git a/documentation/docs/guides/react/01-basics/fetching.mdx b/documentation/docs/guides/react/01-basics/fetching.mdx
new file mode 100644
index 000000000..930870cdb
--- /dev/null
+++ b/documentation/docs/guides/react/01-basics/fetching.mdx
@@ -0,0 +1,33 @@
+---
+sidebar_position: 1
+title: How to fetch with React hook useFetch
+sidebar_label: Fetching
+---
+
+# Fetching
+
+For fetching data use the [`useFetch`](/react/03-hooks/use-fetch.mdx) hook that automates request handling. There are
+tons of [options](/react/03-hooks/use-fetch.mdx#options) to adjust this hook so check out the
+[documentation](/react/03-hooks/use-fetch.mdx).
+
+---
+
+### Examples
+
+```tsx
+import { getUsers, getUser } from "server/user";
+
+...
+
+const { data, error, loading } = useFetch(getUsers)
+
+```
+
+```tsx
+import { getUsers, getUser } from "server/user";
+
+...
+
+const { data, error, loading } = useFetch(getUser.setParams({ userId: 1 }))
+
+```
diff --git a/documentation/docs/guides/04-react/01-core/infinite-scroll.mdx b/documentation/docs/guides/react/01-basics/infinite-scroll.mdx
similarity index 100%
rename from documentation/docs/guides/04-react/01-core/infinite-scroll.mdx
rename to documentation/docs/guides/react/01-basics/infinite-scroll.mdx
diff --git a/documentation/docs/guides/04-react/01-core/optimistic-approach.mdx b/documentation/docs/guides/react/01-basics/optimistic-approach.mdx
similarity index 100%
rename from documentation/docs/guides/04-react/01-core/optimistic-approach.mdx
rename to documentation/docs/guides/react/01-basics/optimistic-approach.mdx
diff --git a/documentation/docs/guides/04-react/01-core/pagination.mdx b/documentation/docs/guides/react/01-basics/pagination.mdx
similarity index 100%
rename from documentation/docs/guides/04-react/01-core/pagination.mdx
rename to documentation/docs/guides/react/01-basics/pagination.mdx
diff --git a/documentation/docs/guides/04-react/01-core/progress.mdx b/documentation/docs/guides/react/01-basics/progress.mdx
similarity index 100%
rename from documentation/docs/guides/04-react/01-core/progress.mdx
rename to documentation/docs/guides/react/01-basics/progress.mdx
diff --git a/documentation/docs/guides/04-react/01-core/queues.mdx b/documentation/docs/guides/react/01-basics/queues.mdx
similarity index 100%
rename from documentation/docs/guides/04-react/01-core/queues.mdx
rename to documentation/docs/guides/react/01-basics/queues.mdx
diff --git a/documentation/docs/guides/04-react/01-core/refreshing.mdx b/documentation/docs/guides/react/01-basics/refreshing.mdx
similarity index 100%
rename from documentation/docs/guides/04-react/01-core/refreshing.mdx
rename to documentation/docs/guides/react/01-basics/refreshing.mdx
diff --git a/documentation/docs/guides/04-react/01-core/request-lifecycle.mdx b/documentation/docs/guides/react/01-basics/request-lifecycle.mdx
similarity index 100%
rename from documentation/docs/guides/04-react/01-core/request-lifecycle.mdx
rename to documentation/docs/guides/react/01-basics/request-lifecycle.mdx
diff --git a/documentation/versioned_docs/version-4.x.x/guides/04-react/01-core/submitting.mdx b/documentation/docs/guides/react/01-basics/submitting.mdx
similarity index 91%
rename from documentation/versioned_docs/version-4.x.x/guides/04-react/01-core/submitting.mdx
rename to documentation/docs/guides/react/01-basics/submitting.mdx
index 9c6c66458..4c6fa7d6d 100644
--- a/documentation/versioned_docs/version-4.x.x/guides/04-react/01-core/submitting.mdx
+++ b/documentation/docs/guides/react/01-basics/submitting.mdx
@@ -6,9 +6,9 @@ sidebar_label: Submitting
# Submitting data
-For submitting and mutating data on server use the [`useSubmit`](/documentation/04-react/02-core/use-submit.mdx) hook
-that automates request handling. There are tons of [options](/documentation/04-react/02-core/use-fetch.mdx#options) to
-adjust this hook so check out the [documentation](/documentation/04-react/02-core/use-submit.mdx).
+For submitting and mutating data on server use the [`useSubmit`](/react/03-hooks/use-submit.mdx) hook that automates
+request handling. There are tons of [options](/react/03-hooks/use-fetch.mdx#options) to adjust this hook so check out
+the [documentation](/react/03-hooks/use-submit.mdx).
---
diff --git a/documentation/docs/guides/04-react/01-core/window-focus-blur.mdx b/documentation/docs/guides/react/01-basics/window-focus-blur.mdx
similarity index 100%
rename from documentation/docs/guides/04-react/01-core/window-focus-blur.mdx
rename to documentation/docs/guides/react/01-basics/window-focus-blur.mdx
diff --git a/documentation/docs/documentation/03-sockets/_category_.json b/documentation/docs/guides/react/02-sockets/_category_.json
similarity index 100%
rename from documentation/docs/documentation/03-sockets/_category_.json
rename to documentation/docs/guides/react/02-sockets/_category_.json
diff --git a/documentation/docs/guides/04-react/02-sockets/emitting.mdx b/documentation/docs/guides/react/02-sockets/emitting.mdx
similarity index 100%
rename from documentation/docs/guides/04-react/02-sockets/emitting.mdx
rename to documentation/docs/guides/react/02-sockets/emitting.mdx
diff --git a/documentation/docs/guides/04-react/02-sockets/listening.mdx b/documentation/docs/guides/react/02-sockets/listening.mdx
similarity index 100%
rename from documentation/docs/guides/04-react/02-sockets/listening.mdx
rename to documentation/docs/guides/react/02-sockets/listening.mdx
diff --git a/documentation/docs/documentation/04-react/_category_.json b/documentation/docs/guides/react/_category_.json
similarity index 100%
rename from documentation/docs/documentation/04-react/_category_.json
rename to documentation/docs/guides/react/_category_.json
diff --git a/documentation/docs/documentation/04-react/03-sockets/_category_.json b/documentation/docs/guides/sockets/_category_.json
similarity index 100%
rename from documentation/docs/documentation/04-react/03-sockets/_category_.json
rename to documentation/docs/guides/sockets/_category_.json
diff --git a/documentation/docs/guides/03-sockets/authentication.mdx b/documentation/docs/guides/sockets/authentication.mdx
similarity index 100%
rename from documentation/docs/guides/03-sockets/authentication.mdx
rename to documentation/docs/guides/sockets/authentication.mdx
diff --git a/documentation/docs/guides/03-sockets/emitting.mdx b/documentation/docs/guides/sockets/emitting.mdx
similarity index 100%
rename from documentation/docs/guides/03-sockets/emitting.mdx
rename to documentation/docs/guides/sockets/emitting.mdx
diff --git a/documentation/docs/guides/03-sockets/listening.mdx b/documentation/docs/guides/sockets/listening.mdx
similarity index 100%
rename from documentation/docs/guides/03-sockets/listening.mdx
rename to documentation/docs/guides/sockets/listening.mdx
diff --git a/documentation/docs/guides/03-sockets/query-params.mdx b/documentation/docs/guides/sockets/query-params.mdx
similarity index 100%
rename from documentation/docs/guides/03-sockets/query-params.mdx
rename to documentation/docs/guides/sockets/query-params.mdx
diff --git a/documentation/docs/guides/sockets/setup.mdx b/documentation/docs/guides/sockets/setup.mdx
new file mode 100644
index 000000000..9ac1e9f59
--- /dev/null
+++ b/documentation/docs/guides/sockets/setup.mdx
@@ -0,0 +1,59 @@
+---
+sidebar_position: 1
+title: Socket Setup Guide
+sidebar_label: Setup
+---
+
+# Setup
+
+---
+
+### Initialize Socket
+
+The first step is to initialize the **[Socket](/sockets/socket.mdx)**. It manage the basic configuration for connection
+to the server and all the sub-systems. We start by determining the `url` of our server.
+
+```tsx title="/src/server/socket.ts"
+import { Socket } from "@hyper-fetch/sockets";
+
+export const socket = new Socket({ url: "ws://localhost:3000" });
+```
+
+### Create Listener
+
+Then, having already prepared connection setup for the server, we use the socket method to create
+**[Listeners](/sockets/listener.mdx)** and assign types to them.
+
+```tsx
+type ChatMessageType = {
+ message: string;
+};
+
+export const onChatMessage = socketInstance.createListener()({
+ endpoint: "chat-message", // endpoint of the event
+});
+```
+
+### Create Emitter
+
+Then, having already prepared connection setup for the server, we use the socket method to create
+**[Emitter](/sockets/emitter.mdx)** and assign types to them.
+
+```tsx
+import { socketInstance } from "./socket";
+
+type ChatMessageType = {
+ message: string;
+};
+
+// Optional
+type AcknowledgementResponseType = {
+ value: string;
+};
+
+export const sendChatMessage = socketInstance.createEmitter()({
+ endpoint: "chat-message", // endpoint of the event
+});
+```
+
+## You're ready to use Hyper Fetch Sockets! 🎊
diff --git a/documentation/docs/guides/06-testing/_category_.json b/documentation/docs/guides/testing/_category_.json
similarity index 100%
rename from documentation/docs/guides/06-testing/_category_.json
rename to documentation/docs/guides/testing/_category_.json
diff --git a/documentation/docs/guides/testing/index.mdx b/documentation/docs/guides/testing/index.mdx
new file mode 100644
index 000000000..f74baa7a1
--- /dev/null
+++ b/documentation/docs/guides/testing/index.mdx
@@ -0,0 +1,78 @@
+---
+sidebar_position: 1
+title: Testing
+sidebar_label: Testing
+---
+
+Testing is one of the best things in Hyper Fetch. With our architecture and focus on global singleton structure, tests
+can be largely based on the application’s configuration. This means tests are no longer sensitive to micro-changes (like
+changing endpoints or types). Everything reacts and adapts to tests or shows the appropriate error – making tests easier
+to maintain and faster to write.
+
+---
+
+## Benefits
+
+- Our setup is always up-to-date with the production solution.
+- No configuration or setup duplication.
+- Easy test maintenance.
+- Faster test builds.
+
+---
+
+## Isolation
+
+The `Client` can become a global module, which will cause it to get mixed between test cases from different files if we
+run them in many workers. Thus, we need to isolate it. This takes two steps:
+
+1. ** Clear the Client**
+
+Use the built-in method `.clear()` to ensure client submodules are initialized and clear of any changes.
+
+2. **Clear the node / runner cache**
+
+As you would with Jest, use the built-in method `.resetModules()` to clean the client global module and reinitialize it.
+Depending on the libraries used, you can check out your environment runner methods or try libraries like **decache**.
+
+---
+
+## Example
+
+In this example, we’re using the great mocking libraries [msw](https://mswjs.io/) and
+[testing-library](https://testing-library.com/), but this solution works with other libraries like
+[Cypress](https://www.cypress.io/). This allows us to simulate real requests and make our tests as close to the
+production environment as possible. We can thus create a really powerful flow that allows us to easily develop tests.
+
+You can build a utilities set that takes a request and uses its method, endpoint and types to create functions that
+allow you to intercept requests.
+
+```tsx
+import { client } from "../api/client";
+import { getUsers } from "../api";
+
+// 'createInterceptor' is some custom method for handling intercepting in the tests we write
+// In our internal test we used MSW as main intercepting layer
+const getUsersInterceptor = createInterceptor(getUsers, {
+ data: [
+ { name: "John", age: 18 },
+ { name: "Matthew", age: 27 },
+ ],
+});
+
+beforeEach(() => {
+ // We need to reset modules cache as client is globally exported module
+ // This way it will not get mixed-up with other test cases running in parallel
+ jest.resetModules();
+ // Clean the environment to make sure it's isolated
+ client.clear();
+});
+
+it("My test", async () => {
+ // Start interceptor listener
+ const mock = getUsersInterceptor();
+
+ // Handle test
+ renderApp();
+ expect(await screen.findByText(mock.data[0])).toBeVisible();
+});
+```
diff --git a/documentation/versioned_docs/version-4.x.x/guides/06-testing/isolation.mdx b/documentation/docs/guides/testing/isolation.mdx
similarity index 97%
rename from documentation/versioned_docs/version-4.x.x/guides/06-testing/isolation.mdx
rename to documentation/docs/guides/testing/isolation.mdx
index bdc17658e..156d1ff1a 100644
--- a/documentation/versioned_docs/version-4.x.x/guides/06-testing/isolation.mdx
+++ b/documentation/docs/guides/testing/isolation.mdx
@@ -1,5 +1,5 @@
---
-sidebar_position: 1
+sidebar_position: 2
title: Testing Isolation
sidebar_label: Isolation
---
diff --git a/documentation/docs/guides/testing/mocking.mdx b/documentation/docs/guides/testing/mocking.mdx
new file mode 100644
index 000000000..3a9c084b6
--- /dev/null
+++ b/documentation/docs/guides/testing/mocking.mdx
@@ -0,0 +1,8 @@
+---
+sidebar_position: 3
+title: Mocking
+sidebar_label: Mocking
+---
+
+Mocking is a technique used to replace real objects with test objects. This is useful when you want to test a function
+or method without actually calling the real object.
diff --git a/documentation/versioned_docs/version-4.x.x/guides/06-testing/stubbing.mdx b/documentation/docs/guides/testing/stubbing.mdx
similarity index 97%
rename from documentation/versioned_docs/version-4.x.x/guides/06-testing/stubbing.mdx
rename to documentation/docs/guides/testing/stubbing.mdx
index dacb397d2..19a671427 100644
--- a/documentation/versioned_docs/version-4.x.x/guides/06-testing/stubbing.mdx
+++ b/documentation/docs/guides/testing/stubbing.mdx
@@ -1,5 +1,6 @@
---
-title: Testing Stubbing
+sidebar_position: 4
+title: Stubbing
sidebar_label: Stubbing
---
diff --git a/documentation/docs/guides/05-typescript/_category_.json b/documentation/docs/guides/typescript/_category_.json
similarity index 100%
rename from documentation/docs/guides/05-typescript/_category_.json
rename to documentation/docs/guides/typescript/_category_.json
diff --git a/examples/next/public/.gitkeep b/documentation/docs/guides/typescript/extend.mdx
similarity index 100%
rename from examples/next/public/.gitkeep
rename to documentation/docs/guides/typescript/extend.mdx
diff --git a/documentation/versioned_docs/version-4.x.x/guides/05-typescript/global-error.mdx b/documentation/docs/guides/typescript/global-error.mdx
similarity index 87%
rename from documentation/versioned_docs/version-4.x.x/guides/05-typescript/global-error.mdx
rename to documentation/docs/guides/typescript/global-error.mdx
index 7bf014615..b73de6c50 100644
--- a/documentation/versioned_docs/version-4.x.x/guides/05-typescript/global-error.mdx
+++ b/documentation/docs/guides/typescript/global-error.mdx
@@ -22,5 +22,5 @@ Remember to add the Error type, which is returned from internal errors like Canc
```ts
type GlobalErrors = Error | { message: string };
-export const client = new Client({ url });
+export const client = new Client<{error: GlobalErrors}>({ url });
```
diff --git a/documentation/versioned_docs/version-4.x.x/guides/05-typescript/local-error.mdx b/documentation/docs/guides/typescript/local-error.mdx
similarity index 84%
rename from documentation/versioned_docs/version-4.x.x/guides/05-typescript/local-error.mdx
rename to documentation/docs/guides/typescript/local-error.mdx
index c03b5c03d..c494f6c1e 100644
--- a/documentation/versioned_docs/version-4.x.x/guides/05-typescript/local-error.mdx
+++ b/documentation/docs/guides/typescript/local-error.mdx
@@ -25,7 +25,7 @@ type LocalErrorType = {
};
};
-const postUser = client.createRequest()({
+const postUser = client.createRequest<{response: ResponseType, payload: RequestType, localError: LocalErrorType}>()({
method: "POST",
endpoint: "/users",
});
diff --git a/documentation/docs/guides/typescript/query-params.mdx b/documentation/docs/guides/typescript/query-params.mdx
new file mode 100644
index 000000000..3c6203f45
--- /dev/null
+++ b/documentation/docs/guides/typescript/query-params.mdx
@@ -0,0 +1,25 @@
+---
+sidebar_position: 6
+title: Setting Query Params Type
+sidebar_label: Query Params
+---
+
+# Query Params Type
+
+Query Params are very often untyped, which may cause maintenance problems. However, this is not the case here, and our
+query params types can be easily added to the request.
+
+---
+
+### Example
+
+```ts
+type QueryParamsType = {
+ search?: string;
+ role?: "Admin" | "User";
+};
+
+const getUsers = client.createRequest<{response: ResponseType, queryParams: QueryParamsType}>()({
+ endpoint: "/users",
+});
+```
diff --git a/documentation/docs/guides/05-typescript/request-extractors.mdx b/documentation/docs/guides/typescript/request-extractors.mdx
similarity index 100%
rename from documentation/docs/guides/05-typescript/request-extractors.mdx
rename to documentation/docs/guides/typescript/request-extractors.mdx
diff --git a/documentation/versioned_docs/version-4.x.x/guides/05-typescript/request-payload-data.mdx b/documentation/docs/guides/typescript/request-payload-data.mdx
similarity index 82%
rename from documentation/versioned_docs/version-4.x.x/guides/05-typescript/request-payload-data.mdx
rename to documentation/docs/guides/typescript/request-payload-data.mdx
index 68ac86b5d..081aa9507 100644
--- a/documentation/versioned_docs/version-4.x.x/guides/05-typescript/request-payload-data.mdx
+++ b/documentation/docs/guides/typescript/request-payload-data.mdx
@@ -20,7 +20,7 @@ type RequestPayloadType = {
age: number;
};
-const postUser = client.createRequest()({
+const postUser = client.createRequest<{response: ResponseType, payload: RequestPayloadType}>()({
method: "POST",
endpoint: "/users",
});
diff --git a/documentation/versioned_docs/version-4.x.x/guides/05-typescript/response-type.mdx b/documentation/docs/guides/typescript/response-type.mdx
similarity index 82%
rename from documentation/versioned_docs/version-4.x.x/guides/05-typescript/response-type.mdx
rename to documentation/docs/guides/typescript/response-type.mdx
index d62173571..10928e823 100644
--- a/documentation/versioned_docs/version-4.x.x/guides/05-typescript/response-type.mdx
+++ b/documentation/docs/guides/typescript/response-type.mdx
@@ -19,7 +19,7 @@ type ResponseType = Array<{
age: number;
}>;
-const getUsers = client.createRequest()({
+const getUsers = client.createRequest<{response: ResponseType}>()({
endpoint: "/users",
});
```
diff --git a/documentation/versioned_docs/version-4.x.x/guides/05-typescript/url-parameters.mdx b/documentation/docs/guides/typescript/url-parameters.mdx
similarity index 86%
rename from documentation/versioned_docs/version-4.x.x/guides/05-typescript/url-parameters.mdx
rename to documentation/docs/guides/typescript/url-parameters.mdx
index 059e9f443..ce7c2cc52 100644
--- a/documentation/versioned_docs/version-4.x.x/guides/05-typescript/url-parameters.mdx
+++ b/documentation/docs/guides/typescript/url-parameters.mdx
@@ -14,7 +14,7 @@ the required parameters to execute the query itself.
### Example
```ts
-const getUser = client.createRequest()({
+const getUser = client.createRequest<{response: ResponseType}>()({
endpoint: "/users/:userId",
});
diff --git a/documentation/docs/hyper-flow/_category_.json b/documentation/docs/hyper-flow/_category_.json
new file mode 100644
index 000000000..c50af513a
--- /dev/null
+++ b/documentation/docs/hyper-flow/_category_.json
@@ -0,0 +1,3 @@
+{
+ "label": "Devtools"
+}
diff --git a/documentation/docs/hyper-flow/download.mdx b/documentation/docs/hyper-flow/download.mdx
new file mode 100644
index 000000000..e72894ac5
--- /dev/null
+++ b/documentation/docs/hyper-flow/download.mdx
@@ -0,0 +1,9 @@
+---
+sidebar_position: 2
+title: Download
+sidebar_label: Download
+---
+
+# Download
+
+## Download
diff --git a/documentation/docs/hyper-flow/getting-started.mdx b/documentation/docs/hyper-flow/getting-started.mdx
new file mode 100644
index 000000000..e7859f80b
--- /dev/null
+++ b/documentation/docs/hyper-flow/getting-started.mdx
@@ -0,0 +1,9 @@
+---
+sidebar_position: 3
+title: Getting Started
+sidebar_label: Getting Started
+---
+
+# Getting Started
+
+## Getting Started
diff --git a/documentation/docs/hyper-flow/index.mdx b/documentation/docs/hyper-flow/index.mdx
new file mode 100644
index 000000000..e8d8e35b0
--- /dev/null
+++ b/documentation/docs/hyper-flow/index.mdx
@@ -0,0 +1,112 @@
+---
+sidebar_position: 1
+title: Hyper Flow
+sidebar_label: Intro
+---
+
+# 🚀 Welcome to Hyper Flow
+
+> **Supercharge your development workflow with Hyper Flow — the ultimate DevTools suite for monitoring, debugging, and
+> optimizing your application's network activity and cache.**
+
+Hyper Flow, part of the Hyper Fetch ecosystem, empowers you to:
+
+- **Visualize** your app's network and cache activity in real time
+- **Debug** requests with ease
+- **Optimize** performance and resource usage
+- **Take control** of every request, queue, and cache entry
+
+---
+
+## 🌟 Why Hyper Flow?
+
+Hyper Flow isn't just another DevTools panel. It's your command center for:
+
+- **Seamless debugging**: Instantly inspect requests, payloads, and responses
+- **Performance insights**: Identify bottlenecks and optimize your app
+- **Cache mastery**: View, manage, and debug cache entries effortlessly
+- **Queue management**: Oversee and control all request queues
+
+---
+
+## 🔍 Explore Hyper Flow Features
+
+This is a list of all the features that Hyper Flow offers.
+
+### 🗺️ Project Overview
+
+ **See the big picture at a glance!**
+
+Get instant clarity on your app's health with a beautiful dashboard that visualizes network and cache stats. Spot
+trends, catch anomalies, and understand your application's behavior in seconds — no more guesswork!
+
+### ⚡ Performance Insights
+
+ **Uncover hidden bottlenecks and boost your
+app's speed!**
+
+Dive deep into request timings, throughput, and performance metrics. Hyper Flow helps you pinpoint slowdowns and
+optimize your network layer for lightning-fast user experiences.
+
+### 🗃️ Cache Management
+
+ **Master your cache, maximize efficiency!**
+
+Visualize, inspect, and control your cache like never before. Instantly see what's stored, what's stale, and what needs
+attention — all in one place. Say goodbye to mysterious cache bugs!
+
+### 📋 Queues List
+
+ **Stay on top of every request!**
+
+Monitor all your request queues in real time. Whether you're handling retries, priorities, or concurrency, Hyper Flow
+gives you the power to manage and troubleshoot with confidence.
+
+### 🔎 Queue Details
+
+ **Zoom in for total control!**
+
+Explore each queue's full history, status, and processing flow. Instantly debug stuck or failed requests and optimize
+your queue strategies for flawless delivery.
+
+### 🌐 Network Requests List
+
+ **Never miss a network event!**
+
+Watch every request as it happens. Filter, search, and analyze your app's traffic in real time — perfect for debugging,
+QA, and performance tuning.
+
+### 🧩 Network Request Details
+
+ **See every byte, every header, every response!**
+
+Drill down into individual requests to inspect payloads, headers, and responses. Instantly spot issues, validate
+integrations, and ensure your API calls are rock solid.
+
+### 🗂️ Cache List
+
+ **Your cache, fully transparent!**
+
+Browse all cached items, check their status, and manage them with a click. No more black-box caching — take full control
+and keep your app running smoothly.
+
+### 🔬 Cache Details
+
+ **Debug and optimize with surgical precision!**
+
+Examine every detail of specific cache entries. Track changes, debug issues, and fine-tune your caching strategy for
+maximum performance.
+
+### 🏠 Application Panel
+
+ **Your DevTools HQ — all features, one place!**
+
+Access a unified dashboard that brings together every Hyper Flow feature. Jump between panels, correlate data, and
+command your app's network and cache with ease.
+
+---
+
+## ✨ Get Started with Hyper Flow
+
+Ready to transform your debugging and optimization workflow? Dive into Hyper Flow and experience the next level of
+developer productivity!
diff --git a/documentation/docs/documentation/05-adapters/axios/_category_.json b/documentation/docs/integrations/adapter-axios/_category_.json
similarity index 100%
rename from documentation/docs/documentation/05-adapters/axios/_category_.json
rename to documentation/docs/integrations/adapter-axios/_category_.json
diff --git a/documentation/docs/integrations/adapter-axios/overview.mdx b/documentation/docs/integrations/adapter-axios/overview.mdx
new file mode 100644
index 000000000..3ba370540
--- /dev/null
+++ b/documentation/docs/integrations/adapter-axios/overview.mdx
@@ -0,0 +1,121 @@
+---
+sidebar_position: 1
+title: Axios Adapter
+sidebar_label: Overview
+---
+
+[Read the API Reference »](/docs/api/adapter-axios/Variables/AxiosAdapter.mdx)
+
+Hyper Fetch's `axios` adapter is a simple integration that allows you to use the popular `axios` HTTP client for making
+requests, while still benefiting from all of Hyper Fetch's features like caching, persistence, and request management.
+
+Using the `axios` adapter gives you the best of both worlds.
+
+---
+
+:::tip Purpose
+
+1. **Leverage `axios`**: Use familiar `axios` options, headers, and error handling.
+2. **Seamless Integration**: Combines `axios` with Hyper Fetch's caching, queuing, and persistence.
+3. **Track Progress**: Get detailed upload and download progress events.
+4. **Full Control**: Access `axios` response details and error objects when needed.
+
+:::
+
+---
+
+## Getting Started
+
+To use the `axios` adapter:
+
+1. Install the package:
+
+```bash npm2yarn2pnpm
+npm install @hyper-fetch/axios
+```
+
+2. Import it and set it on your `Client` instance:
+
+(@import adapter-axios AxiosAdapter type=import)
+
+```tsx
+import { Client } from "@hyper-fetch/core";
+import { axiosAdapter } from "@hyper-fetch/axios";
+
+const client = new Client({ url: "base-url" }).setAdapter(axiosAdapter);
+```
+
+3. ...and voila! It's done. Now you can set `axios` options on your requests.
+
+---
+
+## Usage
+
+You can pass any valid `axios` request configuration options to your Hyper Fetch requests. These options can be set when
+you create a request or when you send it.
+
+Here's an example of how to use some common `axios` options:
+
+```tsx
+import { client } from "./client";
+
+// Create a request with axios-specific options
+const getUsers = client.createRequest()({
+ endpoint: "/users",
+ options: {
+ // highlight-start
+ // Set a 5-second timeout for the request
+ timeout: 5000,
+ // Add authentication credentials
+ auth: {
+ username: "your-username",
+ password: "your-password",
+ },
+ // highlight-end
+ },
+});
+```
+
+Or use the `setOptions` method:
+
+```ts
+import { client } from "./client";
+
+const getUsers = client
+ .createRequest()({
+ endpoint: "/users",
+ })
+ .setOptions({
+ // highlight-start
+ // Set a 5-second timeout for the request
+ timeout: 5000,
+ // Add authentication credentials
+ auth: {
+ username: "your-username",
+ password: "your-password",
+ },
+ // highlight-end
+ });
+```
+
+---
+
+## See More
+
+For a full list of available `axios` request configuration options, please refer to the
+[official axios documentation](https://axios-http.com/docs/req_config).
+
+:::caution Key Differences
+
+While you can use most `axios` options, some are managed by Hyper Fetch to ensure proper integration. You should **not**
+pass the following options, as they will be overwritten by the adapter:
+
+- `url`
+- `baseURL`
+- `method`
+- `data` (use `payload` in `send` method instead)
+- `onUploadProgress` (use `onUploadProgress` in `send` method instead)
+- `onDownloadProgress` (use `onDownloadProgress` in `send` method instead)
+- `signal` (managed by Hyper Fetch for cancellation)
+
+:::
diff --git a/documentation/docs/documentation/05-adapters/firebase/_category_.json b/documentation/docs/integrations/adapter-firebase-admin/_category_.json
similarity index 100%
rename from documentation/docs/documentation/05-adapters/firebase/_category_.json
rename to documentation/docs/integrations/adapter-firebase-admin/_category_.json
diff --git a/documentation/docs/integrations/adapter-firebase-admin/firestore.mdx b/documentation/docs/integrations/adapter-firebase-admin/firestore.mdx
new file mode 100644
index 000000000..499919ba0
--- /dev/null
+++ b/documentation/docs/integrations/adapter-firebase-admin/firestore.mdx
@@ -0,0 +1,109 @@
+---
+sidebar_position: 2
+title: Working with Firestore
+sidebar_label: Firestore
+---
+
+## Available methods
+
+After setting the firestore adapter, we can start performing requests! We should select the appropriate method,
+corresponding with firebase methods. If you want to learn more about available methods - please refer to the firebase
+documentation.
+
+Due to its nature, we've solved the realtime listening a bit differently, and thus - this method is not allowed in a
+standard adapter. For the `onSnapshot`-like usage, please check how to
+**[listen to queries](/docs/integrations/adapter-firebase-admin/realtime-queries)**.
+
+```tsx
+const getReq = client.createRequest()({
+ endpoint: "",
+ method: "getDocs", // "addDoc" | "getDoc" | "getDocs" | "setDoc" | "updateDoc" | "deleteDoc"
+});
+```
+
+### getDocs
+
+```tsx
+const getReq = client.createRequest()({
+ endpoint: "",
+ method: "getDocs",
+});
+
+const { data, status, extra, success, error } = await req.send();
+// Data is an array of objects, each object also contains the __key param.
+```
+
+`extra`:
+
+1. `ref` - collection reference endpoint
+2. `snapshot` - 'raw' `getDocs` firestore collection/query reference snapshot
+
+### getDoc
+
+```tsx
+const req = client
+ .createRequest()({
+ endpoint: ":teaId",
+ method: "getDoc",
+ })
+ .setParams({ teaId: 1 });
+
+const { data, status, extra, success, error } = await req.send();
+// setParams can be also passed in the send() method instead
+```
+
+`extra`:
+
+1. `ref` - document reference endpoint
+2. `snapshot` - 'raw' firestore document reference snapshot
+
+### setDoc
+
+```tsx
+const newData = { origin: "Poland", type: "Green", year: 2023, name: "Pou Ran Do Cha", amount: 10 };
+const setReq = client
+ .createRequest()({
+ endpoint: ":teaId",
+ method: "setDoc",
+ // can also pass options: {merge: true} for achieving the firebase 'merge' option
+ })
+ .setParams({ teaId: 1 })
+ .setData(newData);
+
+await setReq.send();
+const { data } = await getReq.send();
+```
+
+In case of `setDoc` - data returned is the same data as passed for setting.
+
+### addDoc
+
+```tsx
+const addDocReq = client
+ .createRequest()({
+ endpoint: "",
+ method: "addDoc",
+ options: {},
+ })
+ .setData(newData);
+
+await addDocReq.send();
+```
+
+In case of `addDoc` - data returned is the same as passed data for setting + the `__key` param that is id of a newly
+created document.
+
+### deleteDoc
+
+```tsx
+const deleteDocReq = client
+ .createRequest()({
+ endpoint: ":teaId",
+ method: "deleteDoc",
+ })
+ .setParams({ teaId: 1 });
+
+await deleteDocReq;
+```
+
+In case of `deleteDoc` - returned data equals `null`
diff --git a/documentation/docs/integrations/adapter-firebase-admin/overview.mdx b/documentation/docs/integrations/adapter-firebase-admin/overview.mdx
new file mode 100644
index 000000000..17ce752f9
--- /dev/null
+++ b/documentation/docs/integrations/adapter-firebase-admin/overview.mdx
@@ -0,0 +1,93 @@
+---
+sidebar_position: 1
+title: Firebase Admin Adapter
+sidebar_label: Overview
+---
+
+> Hyper Fetch `firebase` packages offer complete integration of `realtime database` and `firestore`, both for frontend
+> and backend, with a single, unified approach for all of them.
+
+## Getting Started
+
+In order to start using the firebase adapter, you have to initialize the firestore/realtime database and set the correct
+adapter on the `client`.
+
+There are two packages to chose from with two adapters each:
+
+1. `@hyper-fetch/firebase` - for working with web realtime and firestore databases:
+ 1. `firebaseAdapter` - for standard REST requests.
+ 2. `firebaseSocketsAdapter` - for realtime listening.
+2. `@hyper-fetch/firebase-admin` - for admin versions of the packages:
+ 1. `firebaseAdminAdapter` - for standard REST requests.
+ 2. `firebaseSocketsAdminAdapter` - for realtime listening.
+
+Both packages have the same unified interface.
+
+```tsx
+import { firebaseAdapter } from "@hyper-fetch/firebase";
+import { initializeApp } from "firebase/app";
+import { getFirestore } from "firebase/firestore";
+
+// Firebase firestore database initialization
+const app = initializeApp({
+ projectId: "demo-test-firestore",
+});
+const db = getFirestore(app);
+
+// Setting up the HyperFetch with a firebase adapter
+const client = new Client({ url: "teas/" }).setAdapter(() => firebaseAdapter(db));
+const getReq = client.createRequest()({
+ endpoint: "",
+ method: "getDocs",
+});
+
+// Checking the results
+const { data, status, extra, success, error } = await getReq.send();
+```
+
+In case of firebase admin, the only difference is the import:
+
+```tsx
+import { firebaseAdminAdapter } from "@hyper-fetch/firebase-admin";
+...
+```
+
+Resulting `response` is an object that contains the following properties:
+
+1. `data` - data returned from the database. Each object returned from the database is enhanced also by the `__key`
+ param that equals id of a given document.
+2. `status` - status indicating whether a request ended with `success`, `error` or `emptyResource`. `emptyResource`
+ occurs when the request to firebase succeeded but no data was returned.
+3. `success` - general information if overall request succeeded (`true`) or failed (`false`)
+4. `error` - contains error object if the request failed.
+5. `extra` - contains additional properties, depending on a method used. For instance, for `getDocs` method - it allows
+ to access `ref` and `snapshot` from firestore firebase.
+
+## Differences from 'raw' firebase
+
+1. If we store an array in firebase, for instance `[a, b, c]`, the query would return the same array. However, if the
+ array stops being sequential - for instance, if `a` and `b` were deleted, firebase would return and object:
+ `{2: 'c', 4: 'e'}`. Hyper Fetch always returns and array. Each object in an array has an additional `__key` property,
+ that indicates the id of a given object.
+
+## Filtering queries
+
+In order to standardize the interface across both admin/web firestore/realtime, the filtering and limiting queries is
+done via setting the `constraints` queryParam:
+
+```tsx
+import { $limit, $orderBy, $where } from "constraints";
+
+const req = client.createRequest()({
+ endpoint: "",
+ method: "getDocs",
+}); // or via setQueryParams method
+const { data } = await req.send({
+ queryParams: { constraints: [$where("type", "==", "Green"), $orderBy("year"), $limit(1)] },
+});
+```
+
+User can pass the array of constrains and filters. Please pay attention to the fact that you need to filter via method
+wrappers provided via `adapter-firebase` package: `$where`, `$orderBy`, `$limit`, `$startAt`, `$startAfter`, `$endAt`,
+`$endAfter`, `$orderByChild`, `$orderByKey`, `$orderByValue`, `$limitToFirst`, `$limitToLast`, `$equalTo`. All of these
+methods work exactly the same as their corresponding firebase equivalents.
diff --git a/documentation/docs/documentation/05-adapters/firebase/04-realtime-queries.mdx b/documentation/docs/integrations/adapter-firebase-admin/realtime-queries.mdx
similarity index 100%
rename from documentation/docs/documentation/05-adapters/firebase/04-realtime-queries.mdx
rename to documentation/docs/integrations/adapter-firebase-admin/realtime-queries.mdx
diff --git a/documentation/docs/integrations/adapter-firebase-admin/realtime.mdx b/documentation/docs/integrations/adapter-firebase-admin/realtime.mdx
new file mode 100644
index 000000000..ce847d9d0
--- /dev/null
+++ b/documentation/docs/integrations/adapter-firebase-admin/realtime.mdx
@@ -0,0 +1,112 @@
+---
+sidebar_position: 3
+title: Working with Realtime database
+sidebar_label: Realtime Database
+---
+
+## Available methods
+
+Our Realtime Database adapter provides all the methods the original offers. Due to its nature, we've solved the realtime
+listening a bit differently, and thus - this method is not allowed in standard adapter. For the `onValue`-like usage,
+please check how to **[listen to queries](/docs/integrations/adapter-firebase-admin/realtime-queries)**.
+
+### get
+
+```tsx
+import { firebaseAdapter } from "@hyper-fetch/firebase";
+
+const client = new Client({ url: "teas/" }).setAdapter(() => firebaseAdapter(realtimeDbWeb));
+const req = client.createRequest()({
+ endpoint: "",
+ method: "get",
+});
+
+const { data, status, extra, success, error } = await req.send();
+```
+
+`extra`:
+
+1. `ref` - reference to the endpoint
+2. `snapshot` - 'raw' snapshot from the result
+
+### set
+
+```tsx
+const setReq = client
+ .createRequest()({
+ endpoint: ":teaId",
+ method: "set",
+ })
+ .setParams({ teaId: 1 })
+ .setData(newData);
+
+const { data, status, extra, success, error } = await req.send();
+```
+
+In case of `set` - data returned is the same data as passed for setting.
+
+`extra`:
+
+1. ref - database reference to the path
+
+You can also **remove data** via set by sending the `{data: null}` object:
+
+```tsx
+const setReq = client
+ .createRequest()({
+ endpoint: ":teaId",
+ method: "set",
+ })
+ .setParams({ teaId: 1 })
+ .setData({ data: null });
+```
+
+### push
+
+```tsx
+const pushReq = client
+ .createRequest()({
+ endpoint: "",
+ method: "push",
+ options: {},
+ })
+ .setData(newData);
+```
+
+In case of `push` - data returned is the same data as passed for setting + the `__key` param that equals id of a newly
+created document.
+
+`extra`:
+
+1. ref - database reference to the path
+2. key - key of the newly created resource
+
+### update
+
+```tsx
+const updateReq = client
+ .createRequest()({
+ endpoint: ":teaId",
+ method: "update",
+ })
+ .setData(newData);
+```
+
+In case of `update` - data returned is the same data as passed for setting.
+
+`extra`:
+
+1. ref - database reference to the path
+
+### remove
+
+```tsx
+const removeReq = client
+ .createRequest()({
+ endpoint: ":teaId",
+ method: "remove",
+ })
+ .setParams({ teaId: 1 });
+```
+
+In case of `remove` - returned data equals `null`
diff --git a/documentation/docs/integrations/adapter-firebase/_category_.json b/documentation/docs/integrations/adapter-firebase/_category_.json
new file mode 100644
index 000000000..ee818d748
--- /dev/null
+++ b/documentation/docs/integrations/adapter-firebase/_category_.json
@@ -0,0 +1,3 @@
+{
+ "label": "Firebase Admin"
+}
diff --git a/documentation/docs/integrations/adapter-firebase/firestore.mdx b/documentation/docs/integrations/adapter-firebase/firestore.mdx
new file mode 100644
index 000000000..c4cd7148a
--- /dev/null
+++ b/documentation/docs/integrations/adapter-firebase/firestore.mdx
@@ -0,0 +1,109 @@
+---
+sidebar_position: 2
+title: Working with Firestore
+sidebar_label: Firestore
+---
+
+## Available methods
+
+After setting the firestore adapter, we can start performing requests! We should select the appropriate method,
+corresponding with firebase methods. If you want to learn more about available methods - please refer to the firebase
+documentation.
+
+Due to its nature, we've solved the realtime listening a bit differently, and thus - this method is not allowed in a
+standard adapter. For the `onSnapshot`-like usage, please check how to
+**[listen to queries](/docs/integrations/adapter-firebase/realtime-queries)**.
+
+```tsx
+const getReq = client.createRequest()({
+ endpoint: "",
+ method: "getDocs", // "addDoc" | "getDoc" | "getDocs" | "setDoc" | "updateDoc" | "deleteDoc"
+});
+```
+
+### getDocs
+
+```tsx
+const getReq = client.createRequest()({
+ endpoint: "",
+ method: "getDocs",
+});
+
+const { data, status, extra, success, error } = await req.send();
+// Data is an array of objects, each object also contains the __key param.
+```
+
+`extra`:
+
+1. `ref` - collection reference endpoint
+2. `snapshot` - 'raw' `getDocs` firestore collection/query reference snapshot
+
+### getDoc
+
+```tsx
+const req = client
+ .createRequest()({
+ endpoint: ":teaId",
+ method: "getDoc",
+ })
+ .setParams({ teaId: 1 });
+
+const { data, status, extra, success, error } = await req.send();
+// setParams can be also passed in the send() method instead
+```
+
+`extra`:
+
+1. `ref` - document reference endpoint
+2. `snapshot` - 'raw' firestore document reference snapshot
+
+### setDoc
+
+```tsx
+const newData = { origin: "Poland", type: "Green", year: 2023, name: "Pou Ran Do Cha", amount: 10 };
+const setReq = client
+ .createRequest()({
+ endpoint: ":teaId",
+ method: "setDoc",
+ // can also pass options: {merge: true} for achieving the firebase 'merge' option
+ })
+ .setParams({ teaId: 1 })
+ .setData(newData);
+
+await setReq.send();
+const { data } = await getReq.send();
+```
+
+In case of `setDoc` - data returned is the same data as passed for setting.
+
+### addDoc
+
+```tsx
+const addDocReq = client
+ .createRequest()({
+ endpoint: "",
+ method: "addDoc",
+ options: {},
+ })
+ .setData(newData);
+
+await addDocReq.send();
+```
+
+In case of `addDoc` - data returned is the same as passed data for setting + the `__key` param that is id of a newly
+created document.
+
+### deleteDoc
+
+```tsx
+const deleteDocReq = client
+ .createRequest()({
+ endpoint: ":teaId",
+ method: "deleteDoc",
+ })
+ .setParams({ teaId: 1 });
+
+await deleteDocReq;
+```
+
+In case of `deleteDoc` - returned data equals `null`
diff --git a/documentation/docs/integrations/adapter-firebase/overview.mdx b/documentation/docs/integrations/adapter-firebase/overview.mdx
new file mode 100644
index 000000000..f27b32482
--- /dev/null
+++ b/documentation/docs/integrations/adapter-firebase/overview.mdx
@@ -0,0 +1,93 @@
+---
+sidebar_position: 1
+title: Firebase Adapter
+sidebar_label: Overview
+---
+
+> Hyper Fetch `firebase` packages offer complete integration of `realtime database` and `firestore`, both for frontend
+> and backend, with a single, unified approach for all of them.
+
+## Getting Started
+
+In order to start using the firebase adapter, you have to initialize the firestore/realtime database and set the correct
+adapter on the `client`.
+
+There are two packages to chose from with two adapters each:
+
+1. `@hyper-fetch/firebase` - for working with web realtime and firestore databases:
+ 1. `firebaseAdapter` - for standard REST requests.
+ 2. `firebaseSocketsAdapter` - for realtime listening.
+2. `@hyper-fetch/firebase-admin` - for admin versions of the packages:
+ 1. `firebaseAdminAdapter` - for standard REST requests.
+ 2. `firebaseSocketsAdminAdapter` - for realtime listening.
+
+Both packages have the same unified interface.
+
+```tsx
+import { firebaseAdapter } from "@hyper-fetch/firebase";
+import { initializeApp } from "firebase/app";
+import { getFirestore } from "firebase/firestore";
+
+// Firebase firestore database initialization
+const app = initializeApp({
+ projectId: "demo-test-firestore",
+});
+const db = getFirestore(app);
+
+// Setting up the HyperFetch with a firebase adapter
+const client = new Client({ url: "teas/" }).setAdapter(() => firebaseAdapter(db));
+const getReq = client.createRequest()({
+ endpoint: "",
+ method: "getDocs",
+});
+
+// Checking the results
+const { data, status, extra, success, error } = await getReq.send();
+```
+
+In case of firebase admin, the only difference is the import:
+
+```tsx
+import { firebaseAdminAdapter } from "@hyper-fetch/firebase-admin";
+...
+```
+
+Resulting `response` is an object that contains the following properties:
+
+1. `data` - data returned from the database. Each object returned from the database is enhanced also by the `__key`
+ param that equals id of a given document.
+2. `status` - status indicating whether a request ended with `success`, `error` or `emptyResource`. `emptyResource`
+ occurs when the request to firebase succeeded but no data was returned.
+3. `success` - general information if overall request succeeded (`true`) or failed (`false`)
+4. `error` - contains error object if the request failed.
+5. `extra` - contains additional properties, depending on a method used. For instance, for `getDocs` method - it allows
+ to access `ref` and `snapshot` from firestore firebase.
+
+## Differences from 'raw' firebase
+
+1. If we store an array in firebase, for instance `[a, b, c]`, the query would return the same array. However, if the
+ array stops being sequential - for instance, if `a` and `b` were deleted, firebase would return and object:
+ `{2: 'c', 4: 'e'}`. Hyper Fetch always returns and array. Each object in an array has an additional `__key` property,
+ that indicates the id of a given object.
+
+## Filtering queries
+
+In order to standardize the interface across both admin/web firestore/realtime, the filtering and limiting queries is
+done via setting the `constraints` queryParam:
+
+```tsx
+import { $limit, $orderBy, $where } from "constraints";
+
+const req = client.createRequest()({
+ endpoint: "",
+ method: "getDocs",
+}); // or via setQueryParams method
+const { data } = await req.send({
+ queryParams: { constraints: [$where("type", "==", "Green"), $orderBy("year"), $limit(1)] },
+});
+```
+
+User can pass the array of constrains and filters. Please pay attention to the fact that you need to filter via method
+wrappers provided via `adapter-firebase` package: `$where`, `$orderBy`, `$limit`, `$startAt`, `$startAfter`, `$endAt`,
+`$endAfter`, `$orderByChild`, `$orderByKey`, `$orderByValue`, `$limitToFirst`, `$limitToLast`, `$equalTo`. All of these
+methods work exactly the same as their corresponding firebase equivalents.
diff --git a/documentation/docs/integrations/adapter-firebase/realtime-queries.mdx b/documentation/docs/integrations/adapter-firebase/realtime-queries.mdx
new file mode 100644
index 000000000..de398a566
--- /dev/null
+++ b/documentation/docs/integrations/adapter-firebase/realtime-queries.mdx
@@ -0,0 +1,79 @@
+---
+sidebar_position: 4
+title: Realtime listening
+sidebar_label: Realtime listening
+---
+
+## Listening to queries - realtime updates
+
+Depending on the product, firebase offers two realtime methods:
+ - `onValue` for Realtime Database
+ - `onSnapshot` for Firestore
+
+In Hyper Fetch, in order to make use of these two methods, we have to use our `hyper-fetch/sockets` package.
+
+```tsx
+import {Socket} from "@hyper-fetch/sockets";
+import {firebaseSocketsAdapter} from "@hyper-fetch/firebase";
+
+const firestoreWebDatabase =
+const socket = new Socket({ url: "teas/", adapter: firebaseSocketsAdapter(firestoreWebDatabase) });
+const onSnapshotRequest = socket.createListener()({
+ name: "",
+ options: { groupByChangeType: true },
+});
+const unmount = await onValueReq.listen({ callback: ({data, extra} => {
+ // do something with data and extra received each time socket gets new data
+})});
+```
+
+As you can see in the presented example:
+1. First we need to initialize the socket itself. Here we need to pass an adapter:
+ - `firebaseSocketsAdapter` - for web version of Realtime Database and Firestore - from the `@hyper-fetch/firebase` package.
+ - `firebaseSocketsAdminAdapter` - for admin version of both databases - from the `@hyper-fetch/-firebase-admin` package.
+
+The adapter accepts initialized database.
+
+2. We need to create a `listener` - here we can pass the additional options, params, etc.
+
+3. We need to actually listen on the request and provide a callback that will fire each time new data arrives. In case of our firebase adapter, callback
+can access two params:
+- `data` - all the received elements.
+- `extra` - additional data:
+ - `ref` - firebase reference to a path
+ - `snapshot` - firebase raw snapshot
+ - `status` - status indicating whether a query succeeded or failed
+
+Listener initialization returns an `unmount` function that allows for closing the channel.
+
+## Additional options
+
+Right now we have only one option for each database type:
+
+### Firestore
+
+1. `groupByChangeType` - if we add this option, the `extra` object will have additional object named `groupedResult`
+```tsx
+const {added, modified, removed} = extra.groupedResult
+```
+Let's suppose we are listening on the `teas/` endpoint. Initially, we receive objects. Then, after some time, a new element
+is added to the list. In the `data` object we receive all the existing elements - 11. However, the new element will be also available via
+`extra.groupedResult.added` list. The same goes for modification of existing elements. All changes are reflected in `added`, `modified`, and `removed`.
+
+### Realtime
+
+1. `onlyOnce` - if we add this option, listener will query for data only once.
+
+## Filtering realtime queries
+
+You can filter realtime queries exactly in the same way as with 'standard' methods. The example below contains a listener that will return data only for
+the object with `type` that equals `Green`:
+
+```tsx
+// Should listen for changes only for Green teas
+const onSnapshotReq = socket.createListener()({
+ name: "",
+ options: { constraints: [$where("type", "==", "Green")] },
+});
+
+```
diff --git a/documentation/docs/integrations/adapter-firebase/realtime.mdx b/documentation/docs/integrations/adapter-firebase/realtime.mdx
new file mode 100644
index 000000000..f0e8149a7
--- /dev/null
+++ b/documentation/docs/integrations/adapter-firebase/realtime.mdx
@@ -0,0 +1,112 @@
+---
+sidebar_position: 3
+title: Working with Realtime database
+sidebar_label: Realtime Database
+---
+
+## Available methods
+
+Our Realtime Database adapter provides all the methods the original offers. Due to its nature, we've solved the realtime
+listening a bit differently, and thus - this method is not allowed in standard adapter. For the `onValue`-like usage,
+please check how to **[listen to queries](/docs/integrations/adapter-firebase/realtime-queries)**.
+
+### get
+
+```tsx
+import { firebaseAdapter } from "@hyper-fetch/firebase";
+
+const client = new Client({ url: "teas/" }).setAdapter(() => firebaseAdapter(realtimeDbWeb));
+const req = client.createRequest()({
+ endpoint: "",
+ method: "get",
+});
+
+const { data, status, extra, success, error } = await req.send();
+```
+
+`extra`:
+
+1. `ref` - reference to the endpoint
+2. `snapshot` - 'raw' snapshot from the result
+
+### set
+
+```tsx
+const setReq = client
+ .createRequest()({
+ endpoint: ":teaId",
+ method: "set",
+ })
+ .setParams({ teaId: 1 })
+ .setData(newData);
+
+const { data, status, extra, success, error } = await req.send();
+```
+
+In case of `set` - data returned is the same data as passed for setting.
+
+`extra`:
+
+1. ref - database reference to the path
+
+You can also **remove data** via set by sending the `{data: null}` object:
+
+```tsx
+const setReq = client
+ .createRequest()({
+ endpoint: ":teaId",
+ method: "set",
+ })
+ .setParams({ teaId: 1 })
+ .setData({ data: null });
+```
+
+### push
+
+```tsx
+const pushReq = client
+ .createRequest()({
+ endpoint: "",
+ method: "push",
+ options: {},
+ })
+ .setData(newData);
+```
+
+In case of `push` - data returned is the same data as passed for setting + the `__key` param that equals id of a newly
+created document.
+
+`extra`:
+
+1. ref - database reference to the path
+2. key - key of the newly created resource
+
+### update
+
+```tsx
+const updateReq = client
+ .createRequest()({
+ endpoint: ":teaId",
+ method: "update",
+ })
+ .setData(newData);
+```
+
+In case of `update` - data returned is the same data as passed for setting.
+
+`extra`:
+
+1. ref - database reference to the path
+
+### remove
+
+```tsx
+const removeReq = client
+ .createRequest()({
+ endpoint: ":teaId",
+ method: "remove",
+ })
+ .setParams({ teaId: 1 });
+```
+
+In case of `remove` - returned data equals `null`
diff --git a/documentation/docs/documentation/05-adapters/graphql/_category_.json b/documentation/docs/integrations/adapter-graphql/_category_.json
similarity index 100%
rename from documentation/docs/documentation/05-adapters/graphql/_category_.json
rename to documentation/docs/integrations/adapter-graphql/_category_.json
diff --git a/documentation/docs/integrations/adapter-graphql/graphql-tag.mdx b/documentation/docs/integrations/adapter-graphql/graphql-tag.mdx
new file mode 100644
index 000000000..b43ecab18
--- /dev/null
+++ b/documentation/docs/integrations/adapter-graphql/graphql-tag.mdx
@@ -0,0 +1,51 @@
+---
+sidebar_position: 4
+title: Using graphql-tag
+sidebar_label: graphql-tag
+---
+
+The `graphql-tag` library is a peer dependency of the GraphQL adapter and is used to parse GraphQL query strings into
+the standard AST format.
+
+:::tip Why use `graphql-tag`?
+
+- **Standardization**: It ensures that your GraphQL queries are valid and conform to the official specification.
+- **Tooling Support**: It enables better tooling support, such as syntax highlighting and autocompletion in your editor.
+- **Readability**: It makes your queries more readable by allowing you to write them as multi-line strings.
+
+:::
+
+---
+
+## Usage
+
+You should use the `gql` tag from `graphql-tag` to define all your queries and mutations. The GraphQL adapter will then
+automatically handle the conversion to a printable string that can be sent to your server.
+
+```ts
+import { Client } from "@hyper-fetch/core";
+import { graphqlAdapter } from "@hyper-fetch/graphql";
+import gql from "graphql-tag";
+
+const client = new Client({ url: "http://localhost:3000/graphql" }).setAdapter(graphqlAdapter);
+
+interface User {
+ user: {
+ username: string;
+ firstName: string;
+ };
+}
+
+const getUser = client.createRequest()({
+ endpoint: gql`
+ query GetUser {
+ user {
+ username
+ firstName
+ }
+ }
+ `,
+});
+
+const { data, error } = await getUser.send();
+```
diff --git a/documentation/docs/integrations/adapter-graphql/mutations.mdx b/documentation/docs/integrations/adapter-graphql/mutations.mdx
new file mode 100644
index 000000000..70cc2cb04
--- /dev/null
+++ b/documentation/docs/integrations/adapter-graphql/mutations.mdx
@@ -0,0 +1,67 @@
+---
+sidebar_position: 3
+title: Working with Mutations
+sidebar_label: Mutations
+---
+
+Mutations are used to modify data on your GraphQL server. This guide will show you how to create and execute mutations
+using Hyper Fetch.
+
+:::tip What you'll learn
+
+- How to create a GraphQL mutation.
+- How to pass variables to a mutation.
+- How to handle mutation responses.
+
+:::
+
+---
+
+## Basic Mutation
+
+Here is a basic example of how to create a mutation to log in a user.
+
+```tsx
+import { Client } from "@hyper-fetch/core";
+import { graphqlAdapter } from "@hyper-fetch/graphql";
+import gql from "graphql-tag";
+
+// 1. Initialize the client
+const client = new Client({ url: "http://localhost:3000/graphql" }).setAdapter(graphqlAdapter);
+
+// 2. Define types for the variables
+type Variables = {
+ username: string;
+ password: string;
+};
+
+// 3. Create the mutation request
+const login = client.createRequest()({
+ endpoint: gql`
+ mutation Login($username: String!, $password: String!) {
+ login(username: $username, password: $password)
+ }
+ `,
+});
+
+// 4. Send the mutation with variables
+const { data, error } = await login.send({
+ data: {
+ variables: {
+ username: "Some username",
+ password: "Some password",
+ },
+ },
+});
+```
+
+Similar to queries, you can also use the `.setData()` method to provide variables for your mutation.
+
+```ts
+const { data, error } = await login
+ .setData({
+ username: "Some username",
+ password: "Some password",
+ })
+ .send();
+```
diff --git a/documentation/docs/integrations/adapter-graphql/overview.mdx b/documentation/docs/integrations/adapter-graphql/overview.mdx
new file mode 100644
index 000000000..ab0f5c2b5
--- /dev/null
+++ b/documentation/docs/integrations/adapter-graphql/overview.mdx
@@ -0,0 +1,158 @@
+---
+sidebar_position: 1
+title: GraphQL Adapter
+sidebar_label: Overview
+---
+
+> The Hyper Fetch GraphQL Adapter provides a seamless way to integrate GraphQL with Hyper Fetch, enabling you to make
+> queries and mutations with ease.
+
+:::tip Purpose
+
+1. **Simplify GraphQL integration** in both server and browser environments.
+2. **Provide a type-safe way** to handle GraphQL operations.
+3. **Offer seamless integration** with the Hyper Fetch ecosystem.
+4. **Support both queries and mutations** with a consistent API.
+
+:::
+
+---
+
+## Installation
+
+To get started, you need to install the `@hyper-fetch/graphql` package. You will also need `graphql` and `graphql-tag`
+which are peer dependencies.
+
+```bash
+npm install @hyper-fetch/graphql graphql graphql-tag
+```
+
+---
+
+## Getting Started
+
+Whether you're developing a server-side GraphQL API or a client-side application that consumes GraphQL data, you can use
+Hyper Fetch GraphQL to interact with it. The setup process is simple and straightforward.
+
+```tsx
+import { Client } from "@hyper-fetch/core";
+import { graphqlAdapter } from "@hyper-fetch/graphql";
+import gql from "graphql-tag";
+
+// 1. Create a client
+const client = new Client({ url: "http://localhost:3000/graphql" }).setAdapter(graphqlAdapter);
+
+// 2. Define an interface for your data
+interface User {
+ username: {
+ username: string;
+ firstName: string;
+ };
+}
+
+// 3. Create a request
+const getUser = client.createRequest()({
+ endpoint: gql`
+ query GetUser {
+ user {
+ username
+ firstName
+ }
+ }
+ `,
+});
+
+// 4. Send the request and get the response
+const { data, error } = await getUser.send();
+```
+
+---
+
+## Queries
+
+To perform a query, create a request with the `gql` tag and your GraphQL query string.
+
+```ts
+import { Client } from "@hyper-fetch/core";
+import { graphqlAdapter } from "@hyper-fetch/graphql";
+import gql from "graphql-tag";
+
+const client = new Client({ url: "http://localhost:3000/graphql" }).setAdapter(graphqlAdapter);
+
+const getUsers = client.createRequest()({
+ endpoint: gql`
+ query GetUsers {
+ users {
+ id
+ name
+ }
+ }
+ `,
+});
+```
+
+---
+
+## Mutations
+
+Mutations work just like queries. Define your mutation string and use it in a request.
+
+```ts
+import { Client } from "@hyper-fetch/core";
+import { graphqlAdapter } from "@hyper-fetch/graphql";
+import gql from "graphql-tag";
+
+const client = new Client({ url: "http://localhost:3000/graphql" }).setAdapter(graphqlAdapter);
+
+const addUser = client.createRequest()({
+ endpoint: gql`
+ mutation AddUser($name: String!) {
+ addUser(name: $name) {
+ id
+ name
+ }
+ }
+ `,
+});
+```
+
+---
+
+## Variables
+
+You can pass variables to your queries and mutations using the `data` option in the `send` method.
+
+```ts
+const { data, error } = await addUser.send({
+ data: {
+ variables: { name: "John Doe" },
+ },
+});
+```
+
+This will pass the `name` variable to the `AddUser` mutation.
+
+---
+
+## Next Steps
+
+Now that you have a basic understanding of the GraphQL adapter, you can explore more advanced topics:
+
+
+
+
diff --git a/documentation/docs/integrations/adapter-graphql/queries.mdx b/documentation/docs/integrations/adapter-graphql/queries.mdx
new file mode 100644
index 000000000..f3cf0dee7
--- /dev/null
+++ b/documentation/docs/integrations/adapter-graphql/queries.mdx
@@ -0,0 +1,104 @@
+---
+sidebar_position: 2
+title: Working with Queries
+sidebar_label: Queries
+---
+
+Queries are used to fetch data from your GraphQL API. With Hyper Fetch, you can define your queries using `graphql-tag`
+and execute them with the configured client.
+
+:::tip What you'll learn
+
+- How to create a basic GraphQL query.
+- How to use TypeScript with your queries.
+- How to pass variables to your queries.
+
+:::
+
+---
+
+## Basic Query
+
+Here's how to create a simple query to fetch a user's data.
+
+```tsx
+import { Client } from "@hyper-fetch/core";
+import { graphqlAdapter } from "@hyper-fetch/graphql";
+import gql from "graphql-tag";
+
+// 1. Initialize Client with adapter
+const client = new Client({ url: "http://localhost:3000/graphql" }).setAdapter(graphqlAdapter);
+
+// 2. Define an interface for your data
+interface User {
+ user: {
+ username: string;
+ firstName: string;
+ };
+}
+
+// 3. Create a request
+const getUser = client.createRequest()({
+ endpoint: gql`
+ query GetUser {
+ user {
+ username
+ firstName
+ }
+ }
+ `,
+});
+
+// 4. Send the request
+const { data, error } = await getUser.send();
+```
+
+---
+
+## Query Variables
+
+You often need to pass variables to your queries to filter results or fetch specific data. You can do this by defining
+variables in your GraphQL query and passing them in the `send` method.
+
+```tsx
+import { Client } from "@hyper-fetch/core";
+import { graphqlAdapter } from "@hyper-fetch/graphql";
+import gql from "graphql-tag";
+
+const client = new Client({ url: "http://localhost:3000/graphql" }).setAdapter(graphqlAdapter);
+
+// 1. Define types for the response and variables
+type User = {
+ username: string;
+ firstName: string;
+};
+type Variables = {
+ userId: string;
+};
+
+// 2. Create the request with variables in the query
+const getUser = client.createRequest<{ user: User }, Variables>()({
+ endpoint: gql`
+ query GetUserById($userId: ID!) {
+ user(id: $userId) {
+ username
+ firstName
+ }
+ }
+ `,
+});
+
+// 3. Pass variables when sending the request
+const { data, error } = await getUser.send({
+ data: {
+ variables: { userId: "1" },
+ },
+});
+```
+
+You can also use the `.setData()` method to set variables before sending the request. This is useful when you want to
+separate setting the data from sending the request.
+
+```ts
+const { data, error } = await getUser.setData({ userId: "1" }).send();
+```
diff --git a/documentation/docs/documentation/06-generators/openapi/_category_.json b/documentation/docs/integrations/codegen-openapi/_category_.json
similarity index 100%
rename from documentation/docs/documentation/06-generators/openapi/_category_.json
rename to documentation/docs/integrations/codegen-openapi/_category_.json
diff --git a/documentation/docs/integrations/codegen-openapi/overview.mdx b/documentation/docs/integrations/codegen-openapi/overview.mdx
new file mode 100644
index 000000000..d565706c4
--- /dev/null
+++ b/documentation/docs/integrations/codegen-openapi/overview.mdx
@@ -0,0 +1,126 @@
+---
+sidebar_position: 1
+title: OpenAPI Codegen
+sidebar_label: Overview
+---
+
+[Read the API Reference »](/docs/api/codegen-openapi/Classes/OpenapiRequestGenerator.mdx)
+
+This guide will walk you through using the Hyper Fetch OpenAPI code generator. This powerful tool automatically creates
+type-safe Hyper Fetch clients, requests, and data models directly from your OpenAPI V3 schema. It streamlines the
+process of integrating with REST APIs, saving you time and reducing boilerplate code.
+
+:::success Swagger to Hyper Fetch
+
+This tool is a great way to get started with Hyper Fetch. It will generate a client, requests and types from your API.
+
+:::
+
+---
+
+:::tip Purpose
+
+By using the OpenAPI code generator, you can:
+
+1. **Automatically generate** a ready-to-use Hyper-Fetch client.
+2. **Create typed requests** for all your API endpoints.
+3. **Define data models** based on your OpenAPI schema components.
+4. **Boost productivity** by eliminating manual setup for API integration.
+
+:::
+
+:::caution Supported Version
+
+Please note that the code generator currently supports **OpenAPI V3 schemas only**. Support for other versions is
+planned for the future.
+
+:::
+
+---
+
+## Getting Started
+
+To start using the request generator, all you need is an OpenAPI V3 JSON schema, available either as a local file or a
+remote URL. You can run the generator using `npx`:
+
+```bash
+npx @hyper-fetch/codegen-openapi --schema https://petstore3.swagger.io/api/v3/openapi.json
+```
+
+This command processes the schema and generates a `openapi.client.ts` file in your current directory. This file contains
+a pre-configured Hyper Fetch client, typed request functions, and all the necessary TypeScript types for your API.
+
+Here's a snippet of what the generated file looks like:
+
+```typescript
+// ... (imports and namespace definitions)
+
+export const client = new Client({ url: "/api/v3" });
+
+// ... (type definitions for schemas)
+export type UpdatePetRequestBody = Paths.UpdatePet.RequestBody;
+export type UpdatePetResponseType = Paths.UpdatePet.Responses.$200;
+
+export type AddPetRequestBody = Paths.AddPet.RequestBody;
+export type AddPetResponseType = Paths.AddPet.Responses.$200;
+
+// ... (request definitions)
+
+export const updatePet = client.createRequest()({
+ method: "PUT",
+ endpoint: "/pet",
+});
+
+export const addPet = client.createRequest()({
+ method: "POST",
+ endpoint: "/pet",
+});
+```
+
+### Naming Convention
+
+The generator follows a consistent naming convention based on the `operationId` from your OpenAPI schema:
+
+- **Request Function**: The function name is the camel-cased `operationId`. For example, `addPet`.
+- **Type Definitions**: Types are named by combining the pascal-cased `operationId` with a suffix indicating the type of
+ data (`ResponseType`, `RequestBody`, `QueryParams`, etc.). For example, `AddPetResponseType` or `AddPetRequestBody`.
+
+---
+
+## Configuration
+
+You can customize the generator's output with several command-line options.
+
+### Output File Name
+
+By default, the output file is named `openapi.client.ts`. You can specify a different name using the `--name` option:
+
+```bash
+npx @hyper-fetch/codegen-openapi --schema --name hyper-fetch.requests.ts
+```
+
+### Base URL
+
+The generator attempts to extract the base URL from the `servers` field in your OpenAPI schema:
+
+```json
+"servers": [
+ {
+ "url": "/api/v3"
+ }
+]
+```
+
+If you need to override this or if the `servers` field is not present, you can provide a base URL with the `--url`
+option:
+
+```bash
+npx @hyper-fetch/codegen-openapi --schema --url https://api.example.com
+```
+
+This will configure the generated client with the specified URL:
+
+```typescript
+// ... generated file
+export const client = new Client({ url: "https://api.example.com" });
+```
diff --git a/documentation/versioned_docs/version-4.x.x/documentation/01-getting-started/_category_.json b/documentation/docs/integrations/getting-started/_category_.json
similarity index 100%
rename from documentation/versioned_docs/version-4.x.x/documentation/01-getting-started/_category_.json
rename to documentation/docs/integrations/getting-started/_category_.json
diff --git a/documentation/docs/integrations/getting-started/community.mdx b/documentation/docs/integrations/getting-started/community.mdx
new file mode 100644
index 000000000..9929cbdb8
--- /dev/null
+++ b/documentation/docs/integrations/getting-started/community.mdx
@@ -0,0 +1,3 @@
+# Community
+
+Add your own packages and integrations.
diff --git a/documentation/docs/integrations/getting-started/index.mdx b/documentation/docs/integrations/getting-started/index.mdx
new file mode 100644
index 000000000..f7b83ff2d
--- /dev/null
+++ b/documentation/docs/integrations/getting-started/index.mdx
@@ -0,0 +1,9 @@
+---
+sidebar_position: 1
+title: Getting Started
+sidebar_label: Getting Started
+---
+
+import { Integrations } from "./integrations/index";
+
+
diff --git a/documentation/docs/integrations/getting-started/integrations/card/card.tsx b/documentation/docs/integrations/getting-started/integrations/card/card.tsx
new file mode 100644
index 000000000..a7232fb2e
--- /dev/null
+++ b/documentation/docs/integrations/getting-started/integrations/card/card.tsx
@@ -0,0 +1,54 @@
+import Link from "@docusaurus/Link";
+import { Description, DocsCard, Noise, Title } from "@site/src/components";
+import { useSidebar } from "@site/src/hooks/use-sidebar";
+import { Section } from "@site/src/modules";
+import clsx from "clsx";
+
+export type CardProps = {
+ section: Section;
+ className?: string;
+};
+
+export function IntegrationCard({ section, className }: CardProps) {
+ const { sidebar } = useSidebar();
+
+ const item = sidebar.find((element) => element.section.label === section.label);
+
+ return (
+
+
+
+
+ {item.section.img && (
+
+
+ {item.section.featured && (
+
+ )}
+
+ )}
+
+ {item.name}
+
+
+
+
+ {item.description}
+
+
+
+
+ );
+}
diff --git a/documentation/docs/integrations/getting-started/integrations/index.ts b/documentation/docs/integrations/getting-started/integrations/index.ts
new file mode 100644
index 000000000..5eb5b72b0
--- /dev/null
+++ b/documentation/docs/integrations/getting-started/integrations/index.ts
@@ -0,0 +1 @@
+export * from "./integrations";
diff --git a/documentation/docs/integrations/getting-started/integrations/integrations.tsx b/documentation/docs/integrations/getting-started/integrations/integrations.tsx
new file mode 100644
index 000000000..f985ecefb
--- /dev/null
+++ b/documentation/docs/integrations/getting-started/integrations/integrations.tsx
@@ -0,0 +1,89 @@
+import { Description, DocsCard, Particles, Title } from "@site/src/components";
+import PageIllustration02 from "@site/static/img/page-illustration-02.svg";
+
+import { IntegrationsList } from "./list/list";
+
+const styles = `
+.theme-doc-breadcrumbs, article header, .theme-doc-version-badge {
+ display: none!important;
+}
+main > div > .row > .col {
+ width: 100%!important;
+ max-width: none!important;
+}
+
+
+`;
+
+export const Integrations = () => {
+ return (
+
+
+
+ {/* Graphic 02 */}
+
+
+ {/* Opacity layer */}
+
+
+ {/* Radial gradient */}
+
+
+ {/* Particles animation */}
+
+
+ {/* Graphic */}
+
+
+
+
+
+
+
+
+ Integrations & Add-ons
+
+
Make it your own
+
+ Unlock the full potential of your workflow, ensuring a cohesive and productive environment.
+
+
+
+
+
+
+
+
+
+ Have an idea for new integrations?
+
+
+ Create and add your own integrations. Place it on this page by creating a Pull Request on github.
+ If you have an idea for a new integration, open a new issue and let us know what you need.
+
+
+
+
+ );
+};
diff --git a/documentation/docs/integrations/getting-started/integrations/list/list.tsx b/documentation/docs/integrations/getting-started/integrations/list/list.tsx
new file mode 100644
index 000000000..4fe35ff98
--- /dev/null
+++ b/documentation/docs/integrations/getting-started/integrations/list/list.tsx
@@ -0,0 +1,69 @@
+/* eslint-disable react/no-array-index-key */
+import { Title } from "@site/src/components";
+import { Code, LucideProps, PlugZap, Server, Usb, Users } from "lucide-react";
+import { integrations } from "@site/src/integrations";
+
+import { IntegrationCard } from "../card/card";
+
+const categories = integrations
+ .filter((section) => section.isPackage)
+ .reduce((acc, item) => {
+ if (!acc[item.category]) {
+ acc[item.category] = [item];
+ } else {
+ acc[item.category].push(item);
+ }
+
+ return acc;
+ }, {});
+
+const categoriesKeys = Object.keys(categories);
+
+const icons: Record<
+ string,
+ React.ForwardRefExoticComponent & React.RefAttributes>
+> = {
+ Plugin: PlugZap,
+ Tools: Code,
+ Adapters: Usb,
+ Service: Server,
+ Community: Users,
+};
+
+export function IntegrationsList() {
+ return (
+
+
+
+ {categoriesKeys.map((key) => (
+
+
+ {key}
+
+
+ {categories[key].map((section, index) => (
+
+ ))}
+
+
+ ))}
+
+
+ );
+}
diff --git a/documentation/docs/integrations/getting-started/integrations/promoted-carousel/promoted-carousel.tsx b/documentation/docs/integrations/getting-started/integrations/promoted-carousel/promoted-carousel.tsx
new file mode 100644
index 000000000..d54ad5b19
--- /dev/null
+++ b/documentation/docs/integrations/getting-started/integrations/promoted-carousel/promoted-carousel.tsx
@@ -0,0 +1,72 @@
+import { useCallback, useRef } from "react";
+import { integrations } from "@site/src/integrations";
+import { Swiper, SwiperSlide, SwiperRef } from "swiper/react";
+import { ArrowLeft, ArrowRight } from "lucide-react";
+import "swiper/css";
+
+import { IntegrationCard } from "../card/card";
+
+export const PromotedCarousel = () => {
+ const sliderRef = useRef(null);
+
+ const handlePrev = useCallback(() => {
+ if (!sliderRef.current) return;
+ sliderRef.current.swiper.slidePrev();
+ }, []);
+
+ const handleNext = useCallback(() => {
+ if (!sliderRef.current) return;
+ sliderRef.current.swiper.slideNext();
+ }, []);
+
+ return (
+ <>
+
+ {integrations
+ .filter((section) => section.isPackage && section.featured)
+ .map((section) => (
+
+
+
+ ))}
+
+
+ {/* Arrows */}
+
+
+ Previous
+
+
+
+ Next
+
+
+
+ >
+ );
+};
diff --git a/documentation/docs/integrations/plugin-devtools/_category_.json b/documentation/docs/integrations/plugin-devtools/_category_.json
new file mode 100644
index 000000000..b49e70a9a
--- /dev/null
+++ b/documentation/docs/integrations/plugin-devtools/_category_.json
@@ -0,0 +1,3 @@
+{
+ "label": "Plugin Devtools"
+}
diff --git a/documentation/docs/integrations/plugin-devtools/index.mdx b/documentation/docs/integrations/plugin-devtools/index.mdx
new file mode 100644
index 000000000..952d25189
--- /dev/null
+++ b/documentation/docs/integrations/plugin-devtools/index.mdx
@@ -0,0 +1,57 @@
+---
+sidebar_position: 1
+title: DevTools Plugin
+sidebar_label: Overview
+---
+
+Devtools plugin allow you to connect your application to a [HyperFlow](/docs/hyper-flow). It allows you to inspect the
+requests and responses, inspect and modify cache and to control the requests.
+
+---
+
+:::tip Purpose
+
+1. Inspect requests and responses
+2. Inspect and modify cache
+3. Control requests and responses
+
+:::
+
+---
+
+## Install the Plugin
+
+Install the ESLint plugin using npm or yarn:
+
+```bash npm2yarn2pnpm
+npm install @hyper-fetch/devtools-plugin
+```
+
+---
+
+## Usage
+
+Import the plugin and use it in your application:
+
+(@import plugin-devtools DevtoolsPlugin type=import)
+
+```tsx
+import { DevtoolsPlugin } from "@hyper-fetch/devtools-plugin";
+
+const client = new Client({ url: "http://localhost:3000" }).addPlugin(
+ DevtoolsPlugin({
+ // highlight-start
+ appName: "My App",
+ // highlight-end
+ }),
+);
+```
+
+(@import plugin-devtools DevtoolsPluginOptions type=returns)
+
+
diff --git a/documentation/docs/integrations/plugin-eslint/_category_.json b/documentation/docs/integrations/plugin-eslint/_category_.json
new file mode 100644
index 000000000..a889c6f81
--- /dev/null
+++ b/documentation/docs/integrations/plugin-eslint/_category_.json
@@ -0,0 +1,3 @@
+{
+ "label": "Plugin ESLint"
+}
diff --git a/documentation/docs/integrations/plugin-eslint/configuration.mdx b/documentation/docs/integrations/plugin-eslint/configuration.mdx
new file mode 100644
index 000000000..f287fc522
--- /dev/null
+++ b/documentation/docs/integrations/plugin-eslint/configuration.mdx
@@ -0,0 +1,75 @@
+---
+sidebar_position: 2
+title: Configuration
+---
+
+# Configuration
+
+This guide explains how to configure the Hyper Fetch ESLint plugin to match your project's needs.
+
+---
+
+## Basic Configuration
+
+After [installing the plugin](/documentation/docs/integrations/plugin-eslint/installation.mdx), you have two options for
+configuration:
+
+1. ### Using the Recommended Configuration
+
+The recommended configuration enables all rules with their suggested severity levels:
+
+```json
+{
+ "plugins": [
+ // ... your other plugins
+ "hyper-fetch"
+ ]
+}
+```
+
+2. ### Manual Configuration
+
+For more control, you can manually configure each rule:
+
+```json
+{
+ "plugins": [
+ // ... your other plugins
+ "hyper-fetch"
+ ],
+ "rules": {
+ // ... your other rules
+ "hyper-fetch/client-generic-types": "error",
+ "hyper-fetch/request-generic-types": "error"
+ }
+}
+```
+
+---
+
+## Rule Severity Levels
+
+Each rule can be set to one of these severity levels:
+
+- `"off"` or `0` - Turn the rule off
+- `"warn"` or `1` - Turn the rule on as a warning (doesn't affect exit code)
+- `"error"` or `2` - Turn the rule on as an error (exit code will be 1)
+
+Example of setting different severity levels:
+
+```json
+{
+ "plugins": ["hyper-fetch"],
+ "rules": {
+ "hyper-fetch/client-generic-types": "error",
+ "hyper-fetch/request-generic-types": "warn"
+ }
+}
+```
+
+---
+
+## Next Steps
+
+Now that you've configured the plugin, proceed to the [Rules](/documentation/docs/integrations/plugin-eslint/rules.mdx)
+section to learn about the specific rules and what issues they help you identify.
diff --git a/documentation/docs/integrations/plugin-eslint/index.mdx b/documentation/docs/integrations/plugin-eslint/index.mdx
new file mode 100644
index 000000000..ab717e1c0
--- /dev/null
+++ b/documentation/docs/integrations/plugin-eslint/index.mdx
@@ -0,0 +1,72 @@
+---
+sidebar_position: 1
+title: ESLint Plugin
+sidebar_label: Overview
+---
+
+# ESLint Plugin
+
+Enhance your development workflow with **`eslint-plugin-hyper-fetch`**, a set of custom ESLint rules designed to catch
+common issues when working with Hyper Fetch. This plugin helps you identify and resolve problems with generic types that
+TypeScript alone might miss, such as typos, missing values, or incorrect type usage.
+
+---
+
+:::tip Purpose
+
+1. Catch generic type issues TypeScript may miss
+2. Prevent runtime errors early
+3. Improve developer experience with clear feedback
+
+:::
+
+---
+
+## Install the Plugin
+
+Install the ESLint plugin using npm or yarn:
+
+```bash npm2yarn2pnpm
+npm install eslint-plugin-hyper-fetch
+```
+
+---
+
+## Quick Start
+
+1. ### Update ESLint Configuration
+
+After installing the plugin, you need to update your ESLint configuration file (`.eslintrc.js`, `.eslintrc.json`, or
+equivalent) to use the plugin.
+
+2. ### Recommended Configuration
+
+The simplest way to use the plugin is to extend the recommended configuration:
+
+```json
+{
+ "extends": [
+ // ... your other extends
+ "plugin:hyper-fetch/recommended"
+ ]
+}
+```
+
+---
+
+## Key Features
+
+- **Type-Safe Generics**: Detects generic type errors that TypeScript may overlook
+- **Immediate Feedback**: Surfaces type-related issues as you code
+- **Fewer Runtime Bugs**: Prevents issues caused by incorrect type usage
+- **Clear Error Messages**: Makes debugging faster and easier
+
+---
+
+:::info Why Use This Plugin?
+
+- Reduce runtime errors by catching mistakes early
+- Improve developer experience with actionable feedback
+- Strengthen your codebase with better type safety
+
+:::
diff --git a/documentation/docs/integrations/plugin-eslint/rules.mdx b/documentation/docs/integrations/plugin-eslint/rules.mdx
new file mode 100644
index 000000000..4aecf1e03
--- /dev/null
+++ b/documentation/docs/integrations/plugin-eslint/rules.mdx
@@ -0,0 +1,110 @@
+---
+sidebar_position: 3
+title: Rules
+---
+
+# Rules
+
+The Hyper Fetch ESLint plugin includes several rules to help you catch common issues when working with Hyper Fetch. This
+page describes each rule, explains what it checks for, and provides examples of code that would trigger the rule.
+
+---
+
+1. ## client-generic-types
+
+This rule ensures proper generic types are used when creating clients with Hyper Fetch. It extends TypeScript's
+functionality to trace issues with object-like generic types that might otherwise be missed.
+
+### Description
+
+The rule checks for:
+
+- Unexpected generic type properties that don't match the expected interface
+- Empty generic type objects (`{}`)
+- Generic types that don't match the expected object-like format
+
+### Examples of Issues Caught
+
+**Unexpected generic type:**
+
+```tsx
+// ❌ Error: Unexpected generic type(s) found: nonExistingGenericType
+import { createClient } from "@hyper-fetch/core";
+const someClient = createClient<{ nonExistingGenericType: any }>({ url: "http://localhost:3000" });
+```
+
+**Empty generic type:**
+
+```tsx
+// ❌ Error: Generic type provided to createClient is empty
+import { createClient } from "@hyper-fetch/core";
+const someClient = createClient<{}>({ url: "http://localhost:3000" });
+```
+
+**Non-object-like generic type:**
+
+```tsx
+// ❌ Error: Generic type provided to createClient is not matching the expected object-like format
+import { createClient } from "@hyper-fetch/core";
+const someClient = createClient({ url: "http://localhost:3000" });
+```
+
+### Configuration
+
+Default severity: `"error"`
+
+---
+
+2. ## request-generic-types
+
+This rule ensures proper generic types are used when creating requests with Hyper Fetch. It extends TypeScript's
+functionality to trace issues with object-like generic types that might otherwise be missed.
+
+### Description
+
+The rule checks for:
+
+- Unexpected generic type properties that don't match the expected interface
+- Empty generic type objects (`{}`)
+- Generic types that don't match the expected object-like format
+
+### Examples of Issues Caught
+
+**Unexpected generic type:**
+
+```tsx
+// ❌ Error: Unexpected generic type(s) found: nonExistingGenericType
+import { client } from "./client";
+const request = client.createRequest<{ nonExistingGenericType: any }>({ endpoint: "/api/users" });
+```
+
+**Empty generic type:**
+
+```tsx
+// ❌ Error: Generic type provided to createRequest is empty
+import { client } from "./client";
+const request = client.createRequest<{}>({ endpoint: "/api/users" });
+```
+
+**Non-object-like generic type:**
+
+```tsx
+// ❌ Error: Generic type provided to createRequest is not matching the expected object-like format
+import { client } from "./client";
+const request = client.createRequest({ endpoint: "/api/users" });
+```
+
+### Configuration
+
+Default severity: `"error"`
+
+---
+
+## When to Use These Rules
+
+These rules are particularly useful for:
+
+1. Large codebases where multiple developers might be working with Hyper Fetch
+2. Projects where type safety is critical
+3. Applications where you want to ensure consistent usage of Hyper Fetch
+4. Preventing subtle type-related bugs that might only manifest at runtime
diff --git a/documentation/docs/react/03-environments/_category_.json b/documentation/docs/react/03-environments/_category_.json
new file mode 100644
index 000000000..d3c8fa40a
--- /dev/null
+++ b/documentation/docs/react/03-environments/_category_.json
@@ -0,0 +1,3 @@
+{
+ "label": "Environments"
+}
diff --git a/documentation/docs/react/03-environments/browser.mdx b/documentation/docs/react/03-environments/browser.mdx
new file mode 100644
index 000000000..06e766dc8
--- /dev/null
+++ b/documentation/docs/react/03-environments/browser.mdx
@@ -0,0 +1,60 @@
+---
+sidebar_position: 1
+title: Browser
+sidebar_label: Browser
+---
+
+> Hyper Fetch is configured to work in a browser environment **out-of-the-box**. This means you can integrate it into
+> any browser-based application without any initial setup.
+
+:::success Ready out-of-the-box
+
+With no additional configuration, Hyper Fetch will automatically handle the browser environment and mixed environments.
+
+:::
+
+---
+
+## More about mixed environments
+
+Hyper Fetch seamlessly supports Server-Side Rendering (SSR) scenarios, requiring no extra configuration to get started.
+It automatically handles the environment, ensuring a smooth experience whether you're rendering on the client or the
+server.
+
+
+
+---
+
+## See more
+
+This is how we handle the browser environment. You can use this as a reference to implement your own set of rules for
+the events.
+
+### Online / Offline status handling
+
+The default events that handle online/offline status in the library are based on the events available in the web browser
+environment. To use mobile device solutions, you can change the code responsible for handling the connection status.
+
+
+
+### Focus / Blur state handling
+
+The default events that handle focus/blur state in the library are based on the events available in the web browser
+environment. To use mobile device solutions, you can change the code responsible for handling the focus/blur state.
+
+
diff --git a/documentation/docs/react/03-environments/electron.mdx b/documentation/docs/react/03-environments/electron.mdx
new file mode 100644
index 000000000..3d572e755
--- /dev/null
+++ b/documentation/docs/react/03-environments/electron.mdx
@@ -0,0 +1,138 @@
+---
+sidebar_position: 3
+title: Electron
+sidebar_label: Electron
+---
+
+**`Electron`** is also supported by `Hyper Fetch`. This library was designed to work with many environments, which is
+why we kept the structure of the base library very generic and modular. While `Hyper Fetch` works out-of-the-box in
+Electron's renderer process due to its browser-like nature, you can leverage Electron's APIs for more robust
+integrations.
+
+:::secondary What you'll learn
+
+- How to handle online/offline status using `is-online` in the main process.
+- How to manage application focus/blur states with `BrowserWindow` events.
+
+:::
+
+---
+
+## Online / Offline status handling
+
+The default events that handle online/offline status in the library are based on the events available in the web browser
+environment. These work in Electron but can sometimes be unreliable for determining actual internet connectivity. For a
+more accurate connection status, you can use Electron's utilities in the main process and communicate with the renderer
+process where `Hyper Fetch` is running.
+
+For example, you can use a library like `is-online` in the main process to periodically check for a connection and
+notify the renderer process via IPC.
+
+**Main Process (`main.js`)**
+
+```javascript
+// In your main electron file
+import { BrowserWindow } from 'electron';
+import isOnline from 'is-online';
+
+// This is an example of how you can check for online status in the main process
+// and send it to the renderer process.
+export const setupOnlineListener = (mainWindow: BrowserWindow) => {
+ let online = false;
+ setInterval(async () => {
+ const isOnlineStatus = await isOnline();
+ if (online !== isOnlineStatus) {
+ online = isOnlineStatus;
+ mainWindow.webContents.send('online-status', online);
+ }
+ }, 5000);
+}
+```
+
+Then, in your renderer process, you can set up your `Client` to listen for these events. Remember to handle
+`contextIsolation` by exposing `ipcRenderer` via a preload script.
+
+**Renderer Process**
+
+```tsx
+import { Client, AppManager } from "@hyper-fetch/core";
+import { ipcRenderer } from "electron"; // Assuming exposed via preload script
+
+export const client = new Client({
+ url: environment.serverUrl,
+ appManager: (instance) =>
+ new AppManager(instance, {
+ initiallyOnline: navigator.onLine,
+ onlineEvent: (setOnline) => {
+ const onlineListener = (event, isOnline: boolean) => setOnline(isOnline);
+ ipcRenderer.on("online-status", onlineListener);
+
+ return () => {
+ ipcRenderer.removeListener("online-status", onlineListener);
+ };
+ },
+ }),
+});
+```
+
+---
+
+## Application focus / blur state
+
+Similarly to the online/offline status, you can handle application focus and blur states more reliably by using
+Electron's `BrowserWindow` events from the main process rather than the browser-based `window` events.
+
+**Main Process (`main.js`)**
+
+```javascript
+// In your main electron file
+import { BrowserWindow } from 'electron';
+
+export const setupFocusListeners = (mainWindow: BrowserWindow) => {
+ mainWindow.on('focus', () => {
+ mainWindow.webContents.send('window-focused');
+ });
+
+ mainWindow.on('blur', () => {
+ mainWindow.webContents.send('window-blurred');
+ });
+}
+```
+
+Then, you can listen for these events in your renderer process and configure the `AppManager`.
+
+**Renderer Process**
+
+```tsx
+import { Client, AppManager } from "@hyper-fetch/core";
+import { ipcRenderer } from "electron"; // Assuming exposed via preload script
+
+export const client = new Client({
+ url: environment.serverUrl,
+ appManager: (instance) =>
+ new AppManager(instance, {
+ focusEvent: (setFocused) => {
+ const listener = () => setFocused();
+ ipcRenderer.on("window-focused", listener);
+
+ return () => {
+ ipcRenderer.removeListener("window-focused", listener);
+ };
+ },
+ blurEvent: (setBlurred) => {
+ const listener = () => setBlurred();
+ ipcRenderer.on("window-blurred", listener);
+
+ return () => {
+ ipcRenderer.removeListener("window-blurred", listener);
+ };
+ },
+ }),
+});
+```
+
+:::success That's it!
+
+Your app is now ready to fully use all of the features of Hyper Fetch.
+
+:::
diff --git a/documentation/docs/react/03-environments/react-native.mdx b/documentation/docs/react/03-environments/react-native.mdx
new file mode 100644
index 000000000..274d57a54
--- /dev/null
+++ b/documentation/docs/react/03-environments/react-native.mdx
@@ -0,0 +1,92 @@
+---
+sidebar_position: 2
+title: React Native
+sidebar_label: React Native
+---
+
+`Hyper Fetch` is designed to be environment-agnostic, providing full support for `React Native`. Its modular
+architecture allows for easy replacement of core components to seamlessly integrate with native device features.
+
+:::secondary What you'll learn
+
+- How to handle online/offline status using `NetInfo`.
+- How to manage application focus/blur states with `AppState`.
+- How to re-fetch data when a screen comes into focus.
+
+:::
+
+## Online and Offline Status
+
+By default, Hyper Fetch listens to browser-based online/offline events. For React Native, you can use the
+[`@react-native-community/netinfo`](https://github.com/react-native-netinfo/react-native-netinfo) library to track the
+device's network status.
+
+First, you need to install the library:
+
+```bash
+npm install --save @react-native-community/netinfo
+```
+
+Then, configure the `appManager` to use `NetInfo` for network state detection. This ensures that Hyper Fetch is always
+aware of the device's connectivity, preventing requests from being sent when the device is offline.
+
+```tsx title="services/client.ts"
+import { Client } from "@hyper-fetch/core";
+import { AppManager } from "@hyper-fetch/react";
+import NetInfo from "@react-native-community/netinfo";
+
+import { environment } from "src/environments";
+import { ServerErrorType } from "src/types";
+
+export const client = new Client({
+ url: environment.serverUrl,
+ appManager: (instance) =>
+ new AppManager(instance, {
+ initiallyOnline: NetInfo.fetch().then((state) => !!state.isConnected),
+ onlineEvent: (setOnline) => {
+ return NetInfo.addEventListener((state) => {
+ setOnline(!!state.isConnected);
+ });
+ },
+ }),
+});
+```
+
+## Application Focus and Blur
+
+To automatically manage requests based on the application's focus state, you can use React Native's `AppState` API. This
+allows Hyper Fetch to pause requests when the app is in the background and resume them when it's back in the foreground.
+
+This configuration tells Hyper Fetch to listen for app state changes. When the app becomes `active`, it's considered
+focused. When it's `inactive` or in the `background`, it's blurred.
+
+```tsx title="services/client.ts"
+import { AppState, AppStateStatus } from "react-native";
+import { Client } from "@hyper-fetch/core";
+import { AppManager } from "@hyper-fetch/react";
+
+import { environment } from "src/environments";
+import { ServerErrorType } from "src/types";
+
+export const client = new Client({
+ url: environment.serverUrl,
+ appManager: (instance) =>
+ new AppManager(instance, {
+ focusEvent: (setFocused) => {
+ const onChange = (status: AppStateStatus) => {
+ setFocused(status === "active");
+ };
+
+ const subscription = AppState.addEventListener("change", onChange);
+
+ return () => subscription.remove();
+ },
+ }),
+});
+```
+
+:::success That's it!
+
+Your app is now ready to fully use all of the features of Hyper Fetch.
+
+:::
diff --git a/documentation/docs/react/04-hooks/_category_.json b/documentation/docs/react/04-hooks/_category_.json
new file mode 100644
index 000000000..2a88a556c
--- /dev/null
+++ b/documentation/docs/react/04-hooks/_category_.json
@@ -0,0 +1,3 @@
+{
+ "label": "Hooks"
+}
diff --git a/documentation/docs/react/04-hooks/use-app-manager.mdx b/documentation/docs/react/04-hooks/use-app-manager.mdx
new file mode 100644
index 000000000..c1911ae9d
--- /dev/null
+++ b/documentation/docs/react/04-hooks/use-app-manager.mdx
@@ -0,0 +1,62 @@
+---
+sidebar_position: 7
+title: React hooks - useAppManager
+sidebar_label: useAppManager
+---
+
+# useAppManager
+
+[Read the API Reference »](/api/react/Hooks/useAppManager.mdx)
+
+**`useAppManager`** allows you to use information about the connection status and screen focus state. It also offers
+options to manipulate its global state. This hook uses the [`AppManager`](/core/managers.mdx) available on the
+[`Client`](/core/client.mdx) instance.
+
+It returns the status of `isOnline` and `isFocused` and the actions that allow you to change them.
+
+---
+
+:::tip Purpose
+
+1. Controls application **online/offline** state
+2. Controls application **window focus/blur** state
+
+:::
+
+---
+
+## Usage
+
+Here is a simple example of how to use the `useAppManager` hook.
+
+### Get the connection status
+
+Online state is the information if application is connected to the internet or not.
+
+```tsx
+const { isOnline, setOnline } = useAppManager(client);
+
+setOnline(true);
+```
+
+### Get the screen focus state
+
+Focus state is the information if user is currently using the application or not.
+
+```tsx
+const { isFocused, setFocused } = useAppManager(client);
+
+setFocused(true);
+```
+
+---
+
+## State and methods
+
+This hook returns the following values.
+
+```tsx
+const values = useAppManager(client);
+```
+
+(@import react useAppManager type=returns)
diff --git a/documentation/docs/react/04-hooks/use-cache.mdx b/documentation/docs/react/04-hooks/use-cache.mdx
new file mode 100644
index 000000000..cf5c9fa25
--- /dev/null
+++ b/documentation/docs/react/04-hooks/use-cache.mdx
@@ -0,0 +1,138 @@
+---
+sidebar_position: 6
+title: React hooks - useCache
+sidebar_label: useCache
+---
+
+# useCache
+
+[Read the API Reference »](/docs/api/react/Hooks/useCache)
+
+The `useCache` hook allows you to interact with the [`Cache`](/docs/core/cache) of a given request. It provides state,
+methods, and event callbacks for cache changes. Ensure that the `cacheKey` is stable and not affected by
+auto-generation, so the hook always references the correct cache entry.
+
+:::tip Purpose
+
+1. Easily **manage and observe the cache** for a specific request in React.
+2. Provides **state and methods** to interact with the cache layer.
+3. Enables the cache **invalidation** for refetching.
+
+:::
+
+---
+
+## Quick Start
+
+Just provide a prepared [`Request`](/docs/core/request) instance to the hook and listen to it's cache state.
+
+:::warning Remember to match the `cacheKey`
+
+Request's `cacheKey` are generated dynamically based on the request's `queryKey` and `params`. If you want to use
+`useCache` hook, you need to ensure that the `cacheKey` is matching the triggered request's `cacheKey`.
+
+For example if your request has params, provide them like:
+
+```ts
+// When fetching data
+const { data } = useFetch(getUser.setParams({ userId: 1 }));
+
+// code-editor-split
+
+// When listening to cache from another component
+const { data } = useCache(getUser.setParams({ userId: 1 }));
+```
+
+:::
+
+```tsx
+import { useCache } from "@better-typed/react";
+
+const { data, error, loading, invalidate, setData, setError, setLoading } = useCache(getUsers);
+```
+
+---
+
+## Invalidate cache
+
+Invalidate the cache for the current request or a custom key.
+
+```tsx
+const { invalidate } = useCache(request);
+
+// Invalidate current request cache
+invalidate();
+
+// Invalidate by custom key (Regex or cacheKey)
+invalidate(cacheKey);
+```
+
+:::info Invalidating cache
+
+In many cases, **you don't need to use** the `useCache` hook to invalidate cache entries. You can call the `invalidate`
+method directly on the cache instance for more flexibility. Do not worry - it is integrated with our hooks, so you can
+use it in the same way as with the `useCache` hook.
+
+```tsx
+import { client } from "./client";
+
+// Invalidate cache for a specific request
+client.cache.invalidate(request);
+
+// Invalidate cache by custom key (Regex or cacheKey)
+client.cache.invalidate(/^getUsers/);
+
+// Invalidate cache by request instance
+client.cache.invalidate(request);
+```
+
+:::
+
+---
+
+## Options
+
+Configuration options for this hook provided as a second parameter.
+
+```tsx
+const { ... } = useCache(request, options)
+```
+
+(@import react UseCacheOptionsType type=returns)
+
+---
+
+## State and methods
+
+This hook returns the following values.
+
+```tsx
+const values = useCache(request);
+```
+
+(@import react useCache type=returns)
+
+
+
+---
+
+## See also
+
+
+
+
diff --git a/documentation/docs/react/04-hooks/use-fetch.mdx b/documentation/docs/react/04-hooks/use-fetch.mdx
new file mode 100644
index 000000000..efc48c623
--- /dev/null
+++ b/documentation/docs/react/04-hooks/use-fetch.mdx
@@ -0,0 +1,298 @@
+---
+sidebar_position: 3
+title: React hooks - useFetch
+sidebar_label: useFetch
+---
+
+# useFetch
+
+[Read the API Reference »](/api/react/Hooks/useFetch.mdx)
+
+The `useFetch` hook is your main tool for **fetching and reading data** from a server in React components. It integrates
+seamlessly with Hyper Fetch's core systems, such as the [`Dispatcher`](/docs/core/dispatcher) and
+[`Cache`](/docs/core/cache), to deliver a robust, reactive, and efficient data-fetching experience.
+
+:::tip Purpose
+
+1. **Declarative data fetching**: Provide a `Request` and let the hook manage the process.
+2. **Automatic state management**: Handles `loading`, `error`, and `data` states for you.
+3. **Built-in reactivity**: Automatically re-fetches data when dependencies change.
+4. **Lifecycle callbacks**: Easily run side effects on success, error, or completion.
+5. **Deep cache integration**: Uses a central cache to avoid redundant requests and boost performance.
+
+:::
+
+> To send data to the server (such as creating, updating, or deleting resources), use the
+> [`useSubmit`](/react/03-hooks/use-submit.mdx) hook instead.
+
+---
+
+## Quick Start
+
+To use `useFetch`, provide a prepared [`Request`](/docs/core/request) instance. The hook returns the current state of
+that request, including the fetched `data`, `loading` status, and any `error` that may have occurred.
+
+```tsx live title="Fetching a list of users" size=md
+import { useFetch } from "@hyper-fetch/react";
+import { getUsers } from "./api/users";
+
+function App() {
+ const { data, loading, error } = useFetch(getUsers);
+
+ if (loading) {
+ return ;
+ }
+
+ if (error) {
+ return (
+
+ {error.message}
+
+ );
+ }
+
+ return (
+
+
Users:
+
+ {data.map((user) => {
+ return {user.name} ;
+ })}
+
+
+ );
+}
+```
+
+
+
+---
+
+## Dependencies
+
+`useFetch` can automatically re-fetch data when its request or dependency array changes. Pass a dependency array in the
+options object (the second argument). When any value in the array changes, the hook triggers a new request.
+
+This is especially useful for fetching data based on props, state, or other dynamic values.
+
+```tsx live title="Re-fetching on dependency change" size=md
+import { useFetch } from "@hyper-fetch/react";
+import { getUsers } from "./api/users";
+
+function App() {
+ const [search, setSearch] = useState("");
+ const { data, loading, error } = useFetch(getUsers.setQueryParams({ search }), {
+ // This will debounce the request for 400ms
+ bounce: true,
+ bounceTime: 400,
+ bounceType: "debounce",
+ });
+
+ return (
+
+
setSearch(e.target.value)} />
+ {data && (
+
+
Users:
+
+ {data.map((user) => {
+ return {user.name} ;
+ })}
+
+
+ )}
+ {data && !data.length && No users found
}
+ {loading && }
+
+ );
+}
+```
+
+---
+
+## Event Handlers
+
+To handle side effects such as notifications, logging, or triggering other actions, `useFetch` provides a set of event
+handler hooks. This keeps your component's rendering logic clean and separates side effects from state management.
+
+1. `onSuccess`: Fires when the request completes successfully. The callback receives the success `response`.
+2. `onError`: Fires when the request results in an error. The callback receives the `error` object.
+3. `onFinished`: Fires when the request finishes, regardless of the outcome.
+
+```tsx live title="Using Event Handlers" size=md
+import { useFetch } from "@hyper-fetch/react";
+import { getUsers } from "./api/users";
+
+const UsersListPage = () => {
+ const { data, onSuccess, onError, onFinished } = useFetch(getUsers);
+
+ onSuccess(({ response }) => {
+ toast({
+ title: "Success",
+ message: "Users fetched successfully",
+ type: "success",
+ });
+ });
+
+ onError(({ error }) => {
+ toast({
+ title: "Error",
+ message: error.message,
+ type: "error",
+ });
+ });
+
+ onFinished(() => {
+ toast({
+ title: "Finished",
+ message: "Finished request",
+ type: "default",
+ });
+ });
+
+ return (
+
+
Users:
+
+ {data?.map((user) => {
+ return {user.name} ;
+ })}
+
+
+ );
+};
+```
+
+---
+
+## Download and Upload Progress
+
+`useFetch` provides two event handlers for tracking download and upload progress:
+
+- `onDownloadProgress`: Fires when the request is downloading data.
+- `onUploadProgress`: Fires when the request is uploading data.
+
+Both handlers receive give you access to a `ProgressType` object containing crucial information about the request's
+progress.
+
+(@import core ProgressType type=returns)
+
+:::success Rich progress tracking
+
+We are providing advanced progress tracking for both download and upload - with ETA, size left, total size, loaded size,
+and more.
+
+:::
+
+```tsx live title="Using Download and Upload Progress" size=md
+import { useFetch } from "@hyper-fetch/react";
+import { postFile } from "./api/files";
+
+const UsersListPage = () => {
+ const { data, onDownloadProgress, onUploadProgress } = useFetch(postFile);
+ const { requests } = useQueue(postFile);
+ console.log(requests);
+
+ onDownloadProgress((progress) => {
+ // Do something with the progress data
+ });
+
+ onUploadProgress((progress) => {
+ // Do something with the progress data
+ });
+
+ return (
+
+
Request Progress
+ {/* Custom component to visualize progress */}
+ {/* Uses 'useQueue' under the hood */}
+
+
+ );
+};
+```
+
+---
+
+## Options
+
+Customize the behavior of `useFetch` by passing an options object as the second argument.
+
+```tsx
+const { ... } = useFetch(request, {
+ disabled: false,
+ dependencies: [],
+ revalidate: true,
+ // ... and more
+});
+```
+
+Below is a full list of available options.
+
+(@import react UseFetchOptionsType type=returns)
+
+
+
+---
+
+## State and Methods
+
+`useFetch` returns an object containing the request's state, helper methods, and event handlers.
+
+```tsx
+const {
+ data,
+ error,
+ loading,
+ status,
+ refetch,
+ onSuccess,
+ // ... and more
+} = useFetch(request);
+```
+
+Below is a full list of returned values.
+
+(@import react UseFetchReturnType type=returns)
+
+
+
+---
+
+## See More
+
+
+
+
+
+
diff --git a/documentation/docs/react/04-hooks/use-queue.mdx b/documentation/docs/react/04-hooks/use-queue.mdx
new file mode 100644
index 000000000..9751c300a
--- /dev/null
+++ b/documentation/docs/react/04-hooks/use-queue.mdx
@@ -0,0 +1,189 @@
+---
+sidebar_position: 5
+title: React hooks - useQueue
+sidebar_label: useQueue
+---
+
+# useQueue
+
+This hook controls the **dispatcher queues**. It uses the [`Dispatcher`](/core/dispatcher.mdx) to read the actual value
+of the queue, which is based on the `queryKey` retrieved from the request passed as the first argument.
+
+A prepared [`Request`](/core/request.mdx) is the minimum requirement for `useQueue`.
+
+[Read the API Reference »](/api/react/Hooks/useQueue.mdx)
+
+---
+
+:::tip Purpose
+
+1. **Queue control for requests**: Manage and observe the queue of requests for a given `Request` instance.
+2. **Fine-grained request lifecycle**: Start, stop, and pause entire queues or individual requests.
+3. **Real-time updates**: Reactively track the state of all requests in the queue.
+4. **Integration with Dispatcher**: Leverages the [`Dispatcher`](/docs/core/dispatcher) for queue management and event
+ updates.
+5. **Advanced queue strategies**: Works best with `one-by-one` dispatching and the `queued` option enabled.
+
+:::
+
+---
+
+## Quick Start
+
+To use `useQueue`, provide a prepared [`Request`](/docs/core/request) instance. The hook returns the current queue state
+and control methods.
+
+```tsx title="Controlling a request queue" size=md
+import { useQueue } from "@hyper-fetch/react";
+import { getUsers } from "./api/users";
+
+function App() {
+ // highlight-start
+ const { requests } = useQueue(getUsers);
+ // highlight-end
+
+ return (
+
+
+ // highlight-start
+ {/* List of currently running requests */}
+ {requests.map((req) => (
+ {req.requestOptions.endpoint}
+ ))}
+ // highlight-end
+
+
+ );
+}
+```
+
+
+
+---
+
+## How it works
+
+**`useQueue`** uses the request's `queryKey` to read and control the Dispatcher queue. It subscribes to Dispatcher
+events to keep the queue state up to date. This hook is ideal for advanced scenarios where you need to:
+
+- Control the execution order of requests
+- Pause, stop, or resume queued requests
+- Monitor the status of all requests in a queue
+- Integrate with custom queueing strategies
+
+It works best with the `one-by-one` dispatching mode and when the `queued` option is set to `true` on the request.
+
+:::caution
+
+Remember to ensure your request's `queryKey` is static when using this hook. If your request uses dynamic params or
+query params, auto-generated keys may cause incorrect queue tracking. Provide a custom `queryKey` when creating the
+request to avoid this issue.
+
+:::
+
+---
+
+## Controlling the Queue
+
+The hook returns methods to control the queue and individual requests:
+
+```tsx
+const { requests, stopped, stop, start, pause } = useQueue(getUsers);
+
+// Control all requests in the queue
+top(); // Stops the queue
+pause(); // Pauses the queue
+start(); // Starts the queue
+
+// Control individual requests
+requests.forEach((req) => {
+ req.stopRequest();
+ req.startRequest();
+});
+```
+
+Read more about the differences between `stop`, `pause`, and `start` in the [`Dispatcher`](/docs/core/dispatcher)
+documentation.
+
+---
+
+## Options
+
+Customize the behavior of `useQueue` by passing an options object as the second argument.
+
+```tsx
+const { ... } = useQueue(request, options);
+```
+
+(@import react UseQueueOptionsType type=returns)
+
+
+
+---
+
+## Returns
+
+`useQueue` returns an object with the current queue state, control methods, and request helpers.
+
+```tsx
+const values = useQueue(request);
+```
+
+(@import react useQueue type=returns)
+
+
+
+#### Request interface
+
+
+
+(@import react QueueRequest type=returns)
+
+
+
+
+
+---
+
+## See More
+
+
+
+
+
+
diff --git a/documentation/docs/react/04-hooks/use-submit.mdx b/documentation/docs/react/04-hooks/use-submit.mdx
new file mode 100644
index 000000000..39e9cb18a
--- /dev/null
+++ b/documentation/docs/react/04-hooks/use-submit.mdx
@@ -0,0 +1,311 @@
+---
+sidebar_position: 4
+title: React hooks - useSubmit
+sidebar_label: useSubmit
+---
+
+# useSubmit
+
+[Read the API Reference »](/api/react/Hooks/useSubmit.mdx)
+
+The `useSubmit` hook is designed for **mutating data** on the server. It provides a powerful and streamlined way to
+handle submissions, such as creating, updating, or deleting resources. It integrates with Hyper Fetch's core systems
+like the [`Dispatcher`](/docs/core/dispatcher) and [`Cache`](/docs/core/cache) to manage request states and data
+consistency.
+
+:::tip Purpose
+
+1. **Simplified mutations**: Easily trigger data-modifying requests with a `submit` function.
+2. **State management**: Automatically handles `submitting`, `error`, and `response` states.
+3. **Lifecycle callbacks**: Provides hooks like `onSubmitSuccess`, `onSubmitError`, and `onSubmitFinished` to manage
+ side effects cleanly.
+4. **Controlled requests**: Fine-grained control over request execution and data submission.
+5. **Deep cache integration**: Leverages the central cache to keep data consistent across the application.
+
+:::
+
+> If you only need to fetch data, consider using the [`useFetch`](/react/03-hooks/use-fetch.mdx) hook.
+
+---
+
+## Quick Start
+
+To use `useSubmit`, provide a prepared [`Request`](/docs/core/request) instance. The hook returns a `submit` function to
+trigger the request, along with state variables like `submitting` to track its progress.
+
+```tsx live title="Creating a new user" size="lg"
+import { useSubmit } from "@hyper-fetch/react";
+import { createUser } from "./api/users";
+
+function App() {
+ const [name, setName] = useState("");
+ const { submit, submitting, onSubmitSuccess, onSubmitError, data } = useSubmit(createUser);
+
+ const handleSubmit = (event) => {
+ event.preventDefault();
+ submit({ data: { name } });
+ };
+
+ onSubmitSuccess(() => {
+ toast({
+ title: "Success",
+ message: "User created successfully!",
+ type: "success",
+ });
+ setName("");
+ });
+
+ onSubmitError((response) => {
+ toast({
+ title: "Error",
+ message: response.error.message,
+ type: "error",
+ });
+ });
+
+ return (
+
+ );
+}
+```
+
+
+
+---
+
+## Initialization
+
+```tsx
+const { submit, submitting, onSubmitSuccess, onSubmitError, onSubmitFinished } = useSubmit(postLogin);
+```
+
+---
+
+## How it works?
+
+**`useSubmit`** executes a request when a `submit()` function returned from it gets triggered. It uses dependency
+tracking to limit re-rendering and improve performance. Under the hood, communication with the core systems is
+established by event emitters. Many `"helper hooks"` (such as `onSubmitSuccess`, `onSubmitError`, `onSubmitFinished`,
+etc.) are returned; these will help handle the request flow and lifecycle. This approach avoids overloading the base
+hook with callback logic. It also helps improve code readability, decreases code complication, and promotes more
+organized code.
+
+```tsx
+import { useSubmit } from "@hyper-fetch/react";
+import { postLogin } from "server";
+
+interface Values {
+ email: string;
+ password: string;
+}
+
+const LoginPage: React.FC = () => {
+ const { submit, submitting, onSubmitSuccess, onSubmitError, onSubmitFinished } = useSubmit(postLogin);
+
+ onSubmitSuccess(({ response }) => {
+ console.log(response); // { token: string, refreshToken: string }
+ });
+
+ onSubmitError(({ response }) => {
+ console.log(response); // { message: string }
+ });
+
+ onSubmitFinished(({ response }) => {
+ const [payload, error, status] = response;
+ console.log(payload); // { token: string, refreshToken: string } | null
+ console.log(error); // { message: string } | null
+ console.log(status); // 200 / 400 / 404 / 500 ...
+ });
+
+ const onSubmit = (values: Values) => {
+ submit({ data: values });
+ };
+
+ return (
+
+
+
+ );
+};
+```
+
+---
+
+## Event Handlers
+
+`useSubmit` provides several hooks to handle side effects at different stages of the request lifecycle. This approach
+keeps your component logic clean by separating actions like showing notifications or redirecting from the submission
+itself.
+
+1. `onSubmitSuccess`: Fires when the request completes successfully. It receives the success `response`.
+2. `onSubmitError`: Fires when the request fails. It receives the `error` object.
+3. `onSubmitFinished`: Fires when the request is finished, regardless of the outcome.
+
+```tsx title="Using Event Handlers"
+import { useSubmit } from "@hyper-fetch/react";
+import { postLogin } from "server";
+
+const LoginPage = () => {
+ const { submit, onSubmitSuccess, onSubmitError, onSubmitFinished } = useSubmit(postLogin);
+
+ onSubmitSuccess(({ response }) => {
+ console.log("Login successful:", response);
+ toast({ title: "Success", message: "Logged in!", type: "success" });
+ });
+
+ onSubmitError(({ error }) => {
+ console.error("Login failed:", error);
+ toast({ title: "Error", message: error.message, type: "error" });
+ });
+
+ onSubmitFinished((response) => {
+ console.log("Request finished", response);
+ });
+
+ const handleLogin = (values) => {
+ submit({ data: values });
+ };
+
+ // ... form rendering logic
+};
+```
+
+---
+
+## Passing Data and Parameters
+
+You can pass data, and parameters to your request in two main ways.
+
+### Statically on the Request
+
+For data that doesn't change, you can set it directly on the [`Request`](/docs/core/request) instance.
+
+```tsx
+const { submit } = useSubmit(patchUser.setParams({ userId: 1 }).setData({ name: "New Name" }));
+
+// Later in your component
+submit();
+```
+
+### Dynamically with the `submit` function
+
+For dynamic data, such as from user input, pass it in the `options` object to the `submit` function. This is the most
+common approach.
+
+```tsx
+const { submit } = useSubmit(patchUser);
+
+const handleSubmit = (id: number, name: string) => {
+ submit({
+ data: { name },
+ params: { userId: id },
+ queryParams: { notify: "true" },
+ });
+};
+```
+
+---
+
+## Options
+
+Customize the behavior of `useSubmit` by passing an options object as the second argument.
+
+```tsx
+const { ... } = useSubmit(request, {
+ disabled: false,
+ // ... and more
+});
+```
+
+Below is a full list of available options.
+
+(@import react UseSubmitOptionsType type=returns)
+
+
+
+---
+
+## State and Methods
+
+`useSubmit` returns an object containing the request's state, the `submit` method, and event handlers.
+
+```tsx
+const {
+ submit,
+ submitting,
+ data,
+ error,
+ status,
+ onSubmitSuccess,
+ // ... and more
+} = useSubmit(request);
+```
+
+Below is a full list of returned values.
+
+(@import react useSubmit type=returns)
+
+
+
+---
+
+## See More
+
+
+
+
+
+
diff --git a/documentation/docs/guides/03-sockets/_category_.json b/documentation/docs/react/05-sockets/_category_.json
similarity index 100%
rename from documentation/docs/guides/03-sockets/_category_.json
rename to documentation/docs/react/05-sockets/_category_.json
diff --git a/documentation/docs/react/05-sockets/use-emitter.mdx b/documentation/docs/react/05-sockets/use-emitter.mdx
new file mode 100644
index 000000000..fdd6ff8cb
--- /dev/null
+++ b/documentation/docs/react/05-sockets/use-emitter.mdx
@@ -0,0 +1,204 @@
+---
+sidebar_position: 4
+title: Sockets emitter
+sidebar_label: useEmitter
+---
+
+# useEmitter
+
+[Read the API Reference »](/docs/api/react/Hooks/useEmitter)
+
+The `useEmitter` hook is your main tool for **sending events** to a server in React components. It integrates seamlessly
+with Hyper Fetch's core systems, particularly the [`Emitter`](/docs/sockets/emitter), to deliver a robust, reactive, and
+efficient event-emitting experience.
+
+:::tip Purpose
+
+1. **Declarative event emitting**: Provide an `Emitter` and let the hook manage the process.
+2. **Automatic connection management**: Handles `connected` state for you.
+3. **Lifecycle callbacks**: Easily run side effects on events, errors, or reconnections.
+4. **Deep core integration**: Uses a central event dispatcher to send events.
+
+:::
+
+> If you intend to `listen` to events from the server, we recommend choosing the
+> [`useListener`](/docs/react/sockets/use-listener) hook.
+
+---
+
+## Quick Start
+
+To use `useEmitter`, provide a prepared [`Emitter`](/docs/sockets/emitter) instance. The hook returns an `emit` function
+to send events and the current state of the socket connection.
+
+First, let's define an emitter.
+
+```tsx
+// src/api/chat.ts
+import { socketInstance } from "./socket";
+
+export const emitMessage = socketInstance.createEmitter()({
+ endpoint: "chat-message", // endpoint of the event
+});
+```
+
+Now, let's use it in a component.
+
+```tsx
+// src/components/MessageComponent.tsx
+import { useEmitter } from "@hyper-fetch/react";
+import { emitMessage } from "./api/chat";
+
+const MessageComponent: React.FC = () => {
+ const { emit, connected } = useEmitter(emitMessage);
+
+ const onSubmit = (values: { message: string }) => {
+ // ResponseDataType is automatically inherited from Emitter class
+ const acknowledge = (error: Error, data: ResponseDataType) => {
+ if (error) {
+ alert("No server response!");
+ } else {
+ alert("Message received on server.");
+ }
+ };
+
+ emit({ data: values }, acknowledge);
+ };
+
+ return (
+
+ );
+};
+```
+
+
+
+---
+
+## Event Handlers
+
+To handle side effects such as notifications, logging, or triggering other actions, `useEmitter` provides a set of event
+handler hooks. This keeps your component's rendering logic clean and separates side effects from state management.
+
+1. `onEvent`: Fires before we send event message.
+2. `onError`: Fires when an error occurs.
+3. `onReconnecting`: Fires when the socket is attempting to reconnect.
+
+```tsx
+import { useEmitter } from "@hyper-fetch/react";
+import { emitMessage } from "./api";
+
+const MessageComponent: React.FC = () => {
+ const { emit, onEvent, onError, onReconnecting } = useEmitter(emitMessage);
+
+ onEvent((emitter) => {
+ // Event before we send event message
+ console.log(emitter); // Emitter instance
+ });
+
+ onError((error) => {
+ console.log(error); // Error Event
+ });
+
+ onReconnecting((reconnectingAttempt) => {
+ console.log(reconnectingAttempt); // 1
+ });
+
+ // ...
+};
+```
+
+---
+
+## Sending Data
+
+Data can be passed in several ways. One option is to use `setData` method on the [`Emitter`](/docs/sockets/emitter).
+
+```tsx
+const { emit } = useEmitter(emitMessage.setData({ message: "New message" }));
+```
+
+However, you may need to pass data dynamically, which requires using the `emit` function.
+
+```tsx
+const { emit } = useEmitter(emitMessage);
+
+const handleSubmit = (message: string) => {
+ // ResponseDataType is automatically inherited from Emitter class
+ emit({ data: { message } }, (error: Error, data: ResponseDataType) => {
+ if (error) {
+ alert("No server response!");
+ } else {
+ alert("Message received on server.");
+ }
+ });
+};
+```
+
+---
+
+## Options
+
+Customize the behavior of `useEmitter` by passing an options object as the second argument.
+
+```tsx
+const { ... } = useEmitter(emitter, options)
+```
+
+(@import react UseEmitterOptionsType type=returns)
+
+
+
+---
+
+## Returns
+
+`useEmitter` returns an object containing the socket's state and helper methods.
+
+```tsx
+const values = useEmitter(emitter);
+```
+
+(@import react useEmitter type=returns)
+
+
+
+---
+
+## See More
+
+
+
+
+
+
diff --git a/documentation/docs/react/05-sockets/use-listener.mdx b/documentation/docs/react/05-sockets/use-listener.mdx
new file mode 100644
index 000000000..4cfd42c6f
--- /dev/null
+++ b/documentation/docs/react/05-sockets/use-listener.mdx
@@ -0,0 +1,172 @@
+---
+sidebar_position: 3
+title: Sockets listener
+sidebar_label: useListener
+---
+
+# useListener
+
+[Read the API Reference »](/api/react/Hooks/useListener.mdx)
+
+The `useListener` hook is your main tool for **listening to real-time events** from a server in React components. It
+hooks into the `Socket` adapter and starts listening for a given event when a component is mounted.
+
+:::tip Purpose
+
+1. **Real-time event handling**: Listen to server-sent events without manual setup.
+2. **Automatic lifecycle management**: Manages socket connections when the component mounts and unmounts.
+3. **Reactive data updates**: Provides the latest `data` from the server as it arrives.
+4. **Connection state tracking**: Exposes `connected` and `connecting` states to build responsive UIs.
+5. **Helper event hooks**: Offers `onEvent`, `onError`, and `onReconnecting` for handling specific socket events.
+
+:::
+
+> If you intend to **send** events to the server, we recommend choosing the
+> [`useEmitter`](/docs/react/05-sockets/use-emitter) hook.
+
+---
+
+## Quick Start
+
+To use `useListener`, provide a `Listener` instance. The hook automatically listens for events and returns the latest
+`data`, `timestamp`, and connection status.
+
+First, create a `Listener` instance using your socket client.
+
+```tsx title="Creating a listener"
+import { socketInstance } from "./socket";
+
+export const onChatMessage = socketInstance.createListener()({
+ endpoint: "chat-message",
+});
+```
+
+Now, use it in your component to listen for new messages. The `onEvent` helper hook lets you react to incoming data and
+update your component's state.
+
+```tsx live title="Listening to chat messages"
+import { useListener } from "@hyper-fetch/react";
+import { onChatMessage } from "./api/socket";
+
+function App() {
+ const [messages, setMessages] = useState([]);
+ const { data, connected, connecting, onEvent, onError, onReconnecting } = useListener(onChatMessage);
+
+ onEvent(({ data: message, error }) => {
+ if (message) {
+ setMessages((prev) => [...prev, message]);
+ }
+ });
+
+ if (!connected && connecting) {
+ return ;
+ }
+
+ return (
+
+ Chat Room
+
+ {!messages.length &&
No messages yet.
}
+ {messages.map((message, i) => (
+
+ {message.text}
+
+ ))}
+
+
+ );
+}
+```
+
+---
+
+## Event Handlers
+
+`useListener` provides a set of event handler hooks to manage the socket lifecycle and react to events without
+cluttering your component's rendering logic.
+
+1. **`onEvent`**: Fires whenever a new event is received from the server.
+2. **`onError`**: Fires when a connection or subscription error occurs.
+3. **`onOpen`**: Fires when the socket connection is successfully opened.
+4. **`onClose`**: Fires when the socket connection is closed.
+5. **`onReconnecting`**: Fires when the socket is attempting to reconnect.
+
+```tsx live title="Using event handlers"
+import { useListener } from "@hyper-fetch/react";
+import { onChatMessage } from "./api/socket";
+
+function App() {
+ const [messages, setMessages] = useState([]);
+ const { onEvent, onError, onOpen, onClose, onReconnecting } = useListener(onChatMessage);
+
+ onEvent(({ data: message }) => {
+ toast({ type: "success", message: `New message: ${message.text}` });
+ setMessages((prev) => [...prev, message]);
+ });
+
+ onError((error) => {
+ toast({ type: "error", message: `Connection error: ${error.message}` });
+ });
+
+ onOpen(() => {
+ toast({ type: "info", message: "Socket connection opened." });
+ });
+
+ onClose(() => {
+ toast({ type: "warning", message: "Socket connection closed." });
+ });
+
+ onReconnecting((attempt) => {
+ toast({ type: "warning", message: `Reconnecting... (attempt ${attempt})` });
+ });
+
+ return (
+
+ Chat Room
+
+ {messages.map((message, i) => (
+
+ {message.text}
+
+ ))}
+
+
+ );
+}
+```
+
+---
+
+## Options
+
+Configuration options for `useListener` must be provided as the second parameter.
+
+```tsx
+const { ... } = useListener(listener, {
+ disabled: false,
+ // ... and more
+});
+```
+
+Below is a full list of available options.
+
+(@import react UseListenerOptionsType type=returns)
+
+
+
+---
+
+## State and Methods
+
+The `useListener` hook returns an object containing the socket's state and helper methods.
+
+```tsx
+const values = useListener(listener);
+```
+
+(@import react useListener type=returns)
diff --git a/documentation/docs/guides/04-react/_category_.json b/documentation/docs/react/_category_.json
similarity index 100%
rename from documentation/docs/guides/04-react/_category_.json
rename to documentation/docs/react/_category_.json
diff --git a/documentation/docs/react/overview.mdx b/documentation/docs/react/overview.mdx
new file mode 100644
index 000000000..7fba96bc0
--- /dev/null
+++ b/documentation/docs/react/overview.mdx
@@ -0,0 +1,97 @@
+---
+sidebar_position: 1
+title: React
+sidebar_label: Overview
+---
+
+> **`React Hyper Fetch`** is a data fetching library that implements the main features of the core library and adapts it
+> to the React environment. It handles fetching, submitting, and queueing requests as well as their management in the
+> system.
+
+Together with the provided hooks, React Hyper Fetch makes maintaining and writing new functionalities faster and easier.
+
+Note: A previously prepared [**request**](/core/request.mdx) is the minimum requirement for using hooks.
+
+:::info
+
+This package provide hooks for both: `core` and `sockets` subpackages.
+
+:::
+
+---
+
+## Usage
+
+To use hooks, we need to initialize the client and request instances that will be consumed as properties. Take a look at
+the [Quick Start](/getting-started/quick-start.mdx) for more examples and check out our React code examples
+
+```tsx
+const { data, error, loading } = useFetch(getUsers);
+```
+
+```tsx
+const { submit, data, error, submitting } = useSubmit(postLogin);
+```
+
+Check our **[react code examples](/guides/04-react/01-core/fetching.mdx)**
+
+---
+
+## Helper hooks
+
+To break down our hook setups into smaller parts, we implemented helper hooks. This enhances code readability; the idea
+is that the main hook returns minor helpers, which lets us segregate our logic into smaller parts. It's quite simple, as
+you can see in the example below:
+
+```tsx
+const {
+ data,
+ error,
+ loading,
+ onRequestStart,
+ onResponseStart,
+ onSuccess,
+ onError,
+ onDownloadProgress,
+ onUploadProgress,
+ onFinished,
+ onAbort,
+ onOffline,
+} = useFetch(getUsers);
+
+onRequestStart(({ details, request }) => {
+ // Do something on query start
+});
+
+onResponseStart(({ response, details, request }) => {
+ // Do something when query starts returning response
+});
+
+onSuccess(({ response, details, request }) => {
+ // Do something on query success
+});
+
+onError(({ response, details, request }) => {
+ // Do something on query fail
+});
+
+onAbort(({ response, details, request }) => {
+ // Do something on query cancellation
+});
+
+onOffline(({ response, details, request }) => {
+ // Do something when query goes stale while offline
+});
+
+onFinished(({ response, details, request }) => {
+ // Do something on query finished (success or false)
+});
+
+onUploadProgress(({ progress, sizeLeft, timeLeft, total, loaded }) => {
+ // Do something on upload
+});
+
+onDownloadProgress(({ progress, sizeLeft, timeLeft, total, loaded }) => {
+ // Do something on download
+});
+```
diff --git a/documentation/docs/react/quick-start.mdx b/documentation/docs/react/quick-start.mdx
new file mode 100644
index 000000000..4ffdfd2da
--- /dev/null
+++ b/documentation/docs/react/quick-start.mdx
@@ -0,0 +1,138 @@
+---
+sidebar_position: 2
+title: Quick Start
+sidebar_label: Quick Start
+---
+
+> Hyper Fetch's React package provides a set of hooks that make it easy to fetch, cache, and manage data in your React
+> applications with minimal setup.
+
+:::secondary What you'll learn
+
+- How to initialize the Hyper-Fetch client
+- How to create a request
+- How to fetch data using the `useFetch` hook
+- How to submit data using the `useSubmit` hook
+
+:::
+
+---
+
+### 1. Initialize the Client
+
+First, you need to create a `Client` instance. This client will hold the configuration for all your requests, such as
+the base URL. It's best to create it in a separate file to easily share it across your application.
+
+```tsx title="client.ts"
+import { Client } from "@hyper-fetch/core";
+
+export const client = new Client({
+ url: "https://jsonplaceholder.typicode.com",
+});
+```
+
+---
+
+### 2. Create a Request
+
+Next, define your requests. A `request` holds all the information about an endpoint, its method, and other
+configurations. These request instances will be used by the hooks.
+
+```ts title="requests.ts"
+import { client } from "./client";
+
+// We can define a type for our user for better type-safety
+type UserType = {
+ id: number;
+ name: string;
+};
+
+// Request for fetching a list of users
+export const getUsers = client.createRequest<{ response: UserType[] }>()({
+ method: "GET",
+ endpoint: "/users",
+});
+
+// Request for creating a new user
+export const createUser = client.createRequest<{ response: UserType; payload: { name: string } }>()({
+ method: "POST",
+ endpoint: "/users",
+});
+```
+
+---
+
+### 3. Fetch Data with `useFetch`
+
+The `useFetch` hook allows you to fetch data from an endpoint and manage the state of the request (loading, error,
+data). It automatically re-fetches data when the component mounts or dependencies change.
+
+Here's how to use it in a component:
+
+```tsx title="Users.tsx"
+import React from "react";
+import { useFetch } from "@hyper-fetch/react";
+import { getUsers } from "./requests";
+
+export const Users = () => {
+ // highlight-next-line
+ const { data, loading, error } = useFetch(getUsers);
+
+ if (loading) {
+ return Loading...
;
+ }
+
+ if (error) {
+ return Error: {error.message}
;
+ }
+
+ return {data?.map((user) => {user.name} )} ;
+};
+```
+
+---
+
+### 4. Submit Data with `useSubmit`
+
+The `useSubmit` hook is designed for mutations like creating, updating, or deleting data. It gives you a `submit`
+function to trigger the request manually.
+
+Here is an example of a form that creates a new user:
+
+```tsx title="AddUserForm.tsx"
+import React, { useState } from "react";
+import { useSubmit } from "@hyper-fetch/react";
+import { createUser } from "./requests";
+
+export const AddUserForm = () => {
+ // highlight-next-line
+ const { submit, submitting, error, data } = useSubmit(createUser);
+ const [name, setName] = useState("");
+
+ const handleSubmit = (e: React.FormEvent) => {
+ e.preventDefault();
+ // highlight-next-line
+ submit({ data: { name } });
+ };
+
+ return (
+
+ );
+};
+```
+
+---
+
+:::success That's it!
+
+You've learned the basics of using Hyper-Fetch with React. You can now build powerful, type-safe data-driven
+applications.
+
+:::
diff --git a/documentation/docs/guides/04-react/02-sockets/_category_.json b/documentation/docs/sockets/_category_.json
similarity index 100%
rename from documentation/docs/guides/04-react/02-sockets/_category_.json
rename to documentation/docs/sockets/_category_.json
diff --git a/documentation/docs/sockets/adapter.mdx b/documentation/docs/sockets/adapter.mdx
new file mode 100644
index 000000000..887d5dc64
--- /dev/null
+++ b/documentation/docs/sockets/adapter.mdx
@@ -0,0 +1,108 @@
+---
+sidebar_position: 6
+title: Adapter
+sidebar_label: Adapter
+---
+
+[Read the API Reference »](/api/sockets/Classes/Adapter.mdx)
+
+Adapter is a class that specify the way how to communicate with the server. It defines the way how to send and receive
+data, how to handle errors, how to handle reconnects, etc. Currently supporting connection types like `Websocket`,
+`Server Sent Events (SSE)` or integrations like `Firebase Realtime Database`.
+
+---
+
+## Built in Adapters
+
+There are two built in adapters - `WebsocketAdapter` and `ServerSentEventsAdapter` providing basic functionality for the
+`Websocket` and `Server Sent Events (SSE)` connection types.
+
+---
+
+### Websocket Adapter
+
+The default adapter is used to communicate with the `Websocket` server.
+
+(@import sockets WebsocketAdapter type=import)
+
+```tsx
+import { WebsocketAdapter } from "@hyper-fetch/sockets";
+
+const socket = new Socket({
+ url: "http://localhost:3000",
+ adapter: WebsocketAdapter(),
+});
+```
+
+
+
+---
+
+### Server Sent Events (SSE) Adapter
+
+The `ServerSentEventsAdapter` is used to communicate with the `Server Sent Events (SSE)` server.
+
+(@import sockets ServerSentEventsAdapter type=import)
+
+```tsx
+import { ServerSentEventsAdapter } from "@hyper-fetch/sockets";
+
+const socket = new Socket({
+ url: "http://localhost:3000",
+ adapter: ServerSentEventsAdapter(),
+});
+```
+
+
+
+---
+
+## Custom Adapter
+
+There is nothing to prevent you from changing this and creating the adapter you need. Thanks to event communication, you
+can set your own adapter as you wish by only fulfilling the typescript requirements. This way you can create your own
+adapters for existing libraries like `socket.io`.
+
+{/* TODO EXAMPLE */}
+
+---
+
+## See More
+
+
+
+
+
+
+
+
diff --git a/documentation/docs/sockets/emitter.mdx b/documentation/docs/sockets/emitter.mdx
new file mode 100644
index 000000000..4ddaca32d
--- /dev/null
+++ b/documentation/docs/sockets/emitter.mdx
@@ -0,0 +1,175 @@
+---
+sidebar_position: 5
+title: Emitter
+sidebar_label: Emitter
+---
+
+[Read the API Reference »](/docs/api/sockets/Classes/Emitter.mdx)
+
+The `Emitter` class is a core component of Hyper Fetch's real-time communication layer, built on top of WebSockets. It
+provides a **structured, type-safe way to define, configure, and send events to a server**. By encapsulating all the
+details for an event—such as its topic and data payload—`Emitter` ensures consistency and predictability in your
+real-time data interactions.
+
+---
+
+:::tip Purpose
+
+- Define **reusable event templates** to create standardized event structures.
+- Enforce a **consistent data schema** for all events.
+- Reliably **send events** to your WebSocket server.
+
+:::
+
+---
+
+## Initialization
+
+Emitter should be initialized from the `Socket` instance with `createEmitter` method. This passes a shared reference to
+the place that manages communication in the application.
+
+```tsx title="Example of Emitter initialization"
+import { socket } from "./socket";
+
+export const sendChatMessage = socket.createEmitter()({
+ topic: "new-message", // topic of the event
+});
+
+export const sendUserStatus = socket.createEmitter()({
+ topic: "user-status", // topic of the event
+});
+```
+
+---
+
+## Emitting Events
+
+You can trigger an event with the `emit` method, which sends data to the server.
+
+### Sending Data
+
+Use the `setData` method to instruct any data to be sent to the server.
+
+```tsx
+sendChatMessage.setData({ message: "message" });
+```
+
+### Emitting
+
+Use the `emit` method to start the event emitting.
+
+```tsx
+sendChatMessage.emit({ message: "message" });
+
+// or
+
+sendChatMessage.setData({ message: "message" }).emit();
+```
+
+
+
+---
+
+## Methods
+
+Using methods on a emitter is different from other classes in Hyper Fetch. This is to ensure isolation between different
+uses, which allows you to avoid overwriting previously-prepared emitters and to dynamically generate keys for queues or
+the cache.
+
+:::danger
+
+Using any method on emitter returns its clone! `We do not return a reference!`
+
+:::
+
+```tsx
+// ❌ WRONG
+
+const emitter = sendMessageEmitter;
+
+emitter.setData({ message: "some message" }); // Returns CLONED emitter with assigned data
+
+emitter.emit(); // Server error - no data
+```
+
+```tsx
+// ✅ Good
+
+const emitter = sendMessageEmitter;
+
+const emitterWithData = emitter.setData({ message: "some message" }); // Returns CLONED emitter with assigned data
+
+emitterWithData.emit(); // Success
+```
+
+
+
+(@import sockets Emitter type=methods&display=table)
+
+
+
+
+
+---
+
+## Parameters
+
+Configuration options for the emitter.
+
+```tsx
+const emitter = socket.createEmitter()({
+ topic: "chat-message",
+ options: {
+ withCredentials: true,
+ },
+});
+```
+
+(@import sockets EmitterOptionsType type=returns)
+
+---
+
+## TypeScript
+
+When creating an emitter with `socket.createEmitter`, you can specify up to generic type to ensure type safety.
+**`PayloadType`** is the expected type of the data payload sent with the event.
+
+```tsx
+import { socket } from "./socket";
+
+const sendChatMessage = socket.createEmitter<{ message: string; author: string }>()({
+ topic: "chat-message",
+});
+
+sendChatMessage.emit({
+ data: { message: "Hello!", author: "Me" }, // Typed payload
+});
+```
+
+---
+
+## See More
+
+
+
+
diff --git a/documentation/docs/sockets/listener.mdx b/documentation/docs/sockets/listener.mdx
new file mode 100644
index 000000000..ae8b1120f
--- /dev/null
+++ b/documentation/docs/sockets/listener.mdx
@@ -0,0 +1,350 @@
+---
+sidebar_position: 4
+title: Listener
+sidebar_label: Listener
+---
+
+[Read the API Reference »](/docs/api/sockets/Classes/Listener.mdx)
+
+The `Listener` class is a key component of Hyper Fetch's real-time communication capabilities. It provides a **powerful,
+type-safe way to define, configure, and manage event listeners** for data coming from a server through sockets. By
+encapsulating all the details needed to listen for an event—such as the topic and data structure—`Listener` ensures
+consistency, predictability, and flexibility in how your application handles real-time updates.
+
+With a strict and predictable data structure, `Listener` makes it easy to build features that react to live events with
+confidence. Its design, especially when paired with TypeScript, helps you create robust, maintainable, and interactive
+applications by ensuring that the data you receive from the server matches the types you expect.
+
+---
+
+:::tip Purpose
+
+1. To create **consistent and reusable event listener templates**.
+2. To **standardize the data schema** for incoming real-time events.
+3. To provide a **consistent API** for listening to events, regardless of the underlying adapter.
+4. To **hold instructions** on how to connect to specific event topics.
+5. To ensure that incoming event data is **strongly-typed** and structured, making it safe and easy to work with.
+
+:::
+
+---
+
+## Initialization
+
+A `Listener` should be initialized from a `Socket` instance using the `createListener` method. This approach ensures
+that the listener shares a common communication manager with the rest of your application, promoting a unified
+architecture for handling real-time data.
+
+```tsx
+import { socket } from "./socket";
+
+export const onChatMessage = socket.createListener()({
+ topic: "chat-message",
+});
+
+export const onUserStatusChange = socket.createListener()({
+ topic: "status",
+});
+```
+
+---
+
+## Usage
+
+### Listening for Events
+
+To begin receiving events, use the `listen` method and provide a callback function. This function will be executed each
+time a new event is received on the specified topic. The data passed to the callback will be automatically typed based
+on the generic you provided during initialization.
+
+```tsx
+onChatMessage.listen({
+ callback: (message) => {
+ // `message` is automatically typed as ChatMessageType
+ console.log(message);
+ },
+});
+```
+
+### Stopping a Listener
+
+The `listen` method returns a function that, when called, will remove that specific listener. This is the standard way
+to clean up and stop listening for events, for example, when a component unmounts.
+
+```tsx
+// The listen method returns a function to remove the listener
+const removeListener = onChatMessage.listen({ callback: (message) => console.log(message) });
+
+// ...sometime later...
+
+// Call the returned function to stop listening
+removeListener();
+```
+
+You can also interact with the underlying adapter to remove listeners, which can be useful for more advanced scenarios,
+such as removing all listeners for a given event topic.
+
+```tsx
+const callback = ({ data }) => console.log(data);
+const unmountListener = onChatMessage.listen({ callback });
+
+// ...
+
+// Remove ALL listeners for the 'chat-message' topic
+socket.adapter.listeners.delete(onChatMessage.topic);
+
+// Remove a *single* specific listener from the 'chat-message' topic
+socket.adapter.listeners.get(onChatMessage.topic)?.delete(callback);
+```
+
+### Listen Only Once
+
+If you only need to handle the next event that comes in, you can simply call the `removeListener` function from within
+your callback.
+
+```tsx
+const removeEvent = onChatMessage.listen({
+ callback: (message) => {
+ console.log(message);
+ removeEvent(); // Stop listening after the first event
+ },
+});
+```
+
+---
+
+## Features
+
+Here are some of the features of the `Listener` class.
+
+---
+
+### Dynamic Topics
+
+Listeners support dynamic topics with parameters, similar to requests. This allows you to create reusable listener
+templates for resources that require an identifier, such as a specific chat room or user.
+
+Define the parameter in the `topic` string with a colon prefix (e.g., `:id`).
+
+```ts
+export const onNoteChange = socket.createListener()({
+ topic: "notes/:noteId",
+});
+```
+
+Then, use the `setParams` method to provide a value for the parameter before you start listening. Each listener with a
+different parameter will be treated as a separate event stream.
+
+```ts
+// Listen to events for note with ID 1
+onNoteChange.setParams({ noteId: 1 }).listen(/* ... */);
+
+// Listen to events for note with ID 2
+onNoteChange.setParams({ noteId: 2 }).listen(/* ... */);
+```
+
+---
+
+### Global Data Hooks
+
+You can use the `onData` method to create a "global" hook for a listener template. This callback will be triggered for
+_every_ event that matches the listener's topic, even when dynamic parameters are used. It's an excellent way to
+centralize logic that needs to react to any event of a certain type, regardless of its specific parameters.
+
+```ts
+export const onNoteChange = socket
+ .createListener()({
+ topic: "notes/:noteId",
+ })
+ .onData((event) => {
+ // This will be called for any note change, regardless of the 'noteId'
+ console.log("A note changed:", event.data);
+ });
+
+onNoteChange.setParams({ noteId: 1 }).listen(/* ... */);
+onNoteChange.setParams({ noteId: 2 }).listen(/* ... */);
+
+// The onData callback will fire for events on both `notes/1` and `notes/2`
+```
+
+---
+
+### Integration with Hyper Fetch
+
+A powerful use case for the `onData` hook is to create a seamless integration with Hyper Fetch's caching layer. When you
+receive a real-time update, you can use it to instantly update the relevant cached data from a `Request`. This keeps
+your application's state synchronized without needing to re-fetch data from the server.
+
+Here's an example of updating a cached note when an update event is received via a socket.
+
+```ts
+// 1. Your core client and request setup
+const client = new Client({ url: "http://localhost:3000" });
+const getNote = client.createRequest()({
+ topic: "/notes/:noteId",
+});
+
+// 2. Your realtime listener with a data hook
+export const onNoteChange = socket
+ .createListener()({
+ topic: "notes/:noteId",
+ })
+ .onData((event) => {
+ const { noteId } = event.data;
+
+ // 3. Create a request instance that matches the cache entry
+ const noteRequest = getNote.setParams({ noteId });
+
+ // 4. Update the cache with the new data from the socket event
+ client.cache.update(noteRequest, (prevData) => {
+ return { ...prevData, data: event.data };
+ });
+ });
+```
+
+
+
+---
+
+## Methods
+
+The `Listener` class offers a suite of methods to configure and interact with a listener instance. You can find a
+comprehensive list of these methods and their detailed descriptions in the API reference.
+
+
+
+(@import sockets Listener type=methods&display=table)
+
+
+
+
+
+It is crucial to understand how methods on a `Listener` instance operate to ensure predictable behavior in your
+application.
+
+:::danger Methods Return Clones
+
+Methods on a `Listener` instance (e.g., `setParams`, `setOptions`) do not modify the original listener instance in
+place. Instead, they return a **new, cloned instance** of the listener with the specified modifications applied. The
+original listener instance remains unchanged.
+
+**Always use the returned new instance for subsequent operations.** This immutable approach ensures isolation between
+different listener configurations and prevents unintended side effects.
+
+:::
+
+```tsx
+// ❌ WRONG
+const listener = onChatMessage;
+
+// This returns a *new* listener instance, but it's not being assigned or used.
+// The original `listener` variable remains unchanged.
+listener.setOptions({ ... });
+
+// This will listen without the options you intended to apply.
+listener.listen();
+```
+
+```tsx
+// ✅ CORRECT
+const listener = onChatMessage;
+
+// Assign the new, cloned listener with options to a new variable
+const listenerWithOptions = listener.setOptions({ ... });
+
+// Use the correctly configured listener
+listenerWithOptions.listen();
+
+// ✅ Also correct (method chaining)
+onChatMessage
+ .setOptions({ ... })
+ .listen();
+```
+
+---
+
+## Configuration
+
+You can provide additional configuration options when creating a listener to customize its behavior. These options are
+passed in the object to `createListener`.
+
+```ts
+// 1. Initialize the socket
+const socket = new Socket({
+ url: "ws://localhost:3000",
+});
+
+// 2. Create the listener template
+const listener = socket.createListener<{ message: string }>()({
+ topic: "chat-message",
+});
+```
+
+(@import sockets ListenerOptionsType type=returns)
+
+---
+
+## TypeScript
+
+The `Listener` class is designed with TypeScript at its core to provide a superior developer experience and robust type
+safety for real-time events.
+
+### Response Type
+
+When you create a listener, you should provide the type of the data you expect to receive in the event as a generic.
+This ensures that the `data` passed to your `listen` and `onData` callbacks is fully typed, enabling autocompletion and
+preventing common errors.
+
+```ts
+// Define the type for your event data
+type ChatMessageType = {
+ id: string;
+ author: string;
+ message: string;
+ timestamp: number;
+};
+
+// Provide it as a generic to createListener
+const onChatMessage = socket.createListener()({
+ topic: "chat-message",
+});
+
+onChatMessage.listen(({ data }) => {
+ // `data` is now strongly-typed as ChatMessageType
+ console.log(data.message);
+ console.log(data.author);
+ // error-next-line
+ console.log(data.nonExistentProperty); // TypeScript Error
+});
+```
+
+This simple yet powerful feature eliminates guesswork and ensures that your application correctly handles the data
+structures sent by the server.
+
+---
+
+## See More
+
+
+
+
diff --git a/documentation/docs/sockets/overview.mdx b/documentation/docs/sockets/overview.mdx
new file mode 100644
index 000000000..6ecc68d26
--- /dev/null
+++ b/documentation/docs/sockets/overview.mdx
@@ -0,0 +1,157 @@
+---
+sidebar_position: 1
+title: Sockets Overview
+sidebar_label: Overview
+---
+
+import { LinkCard } from "@site/src/components";
+
+# Overview
+
+> The Sockets module brings real-time, event-driven communication to Hyper Fetch, enabling seamless data exchange over
+> persistent connections. Designed for flexibility and type safety, it empowers you to build robust, scalable
+> applications with minimal effort.
+
+---
+
+## Why Sockets?
+
+Modern applications often require real-time updates-think chat apps, live dashboards, or collaborative tools. Our
+sockets package provides a unified, typesafe API for working with connections like WebSockets, Server-Sent Events (SSE),
+while supporting custom adapters for libraries like Firebase Realtime Database.
+
+:::note Our approach
+
+Sockets is built on the same principles as the core Hyper Fetch package: consistency, type safety, and developer
+experience. It extends these ideas to the world of real-time data.
+
+:::
+
+---
+
+## Typesafe realtime
+
+Handling realtime data exchange such as with WebSockets or Server-Sent Events (SSE) presents unique challenges,
+particularly around maintaining type safety as your application grows. The library addresses this by exposing dedicated
+Listener and Emitter classes, each with their own explicit types for responses and payloads.
+
+This means that when you use a listener, such as `chatMessageListener`, you always know the exact type of data being
+handled. Similarly, when emitting data, you have clear expectations for the payload structure.
+
+This approach is especially powerful in projects with multiple listeners and emitters, ensuring type safety and
+maintainability even as your application scales.
+
+```tsx
+import { socketClient } from "./socket-client";
+
+const socket = new Socket({
+ url: "ws://localhost:3000",
+});
+
+const chatMessageListener = socketClient.createListener<{ message: string }>({
+ url: "chat-message",
+});
+
+chatMessageListener.listen({
+ callback: ({ data }) => {
+ console.log(data); // { message: string }
+ },
+});
+```
+
+---
+
+## Listener templates
+
+Usual approach to sockets it to use the `.on()` method where you have to define the topic and the callback. Our approach
+is a bit different. Just like in the core-package we prefer to create reusable templates for the listeners. They keep
+the information about expected message data type and other. This way you can use the listener template in multiple
+places with full type-safety.
+
+```tsx
+import { Socket } from "@hyper-fetch/sockets";
+
+// 1. Initialize the socket
+const socket = new Socket({
+ url: "ws://localhost:3000",
+});
+
+// 2. Create the listener template
+const chatMessageListener = socket.createListener<{ message: string }>({
+ topic: "chat-message",
+});
+
+// 3. Listen to the chat message
+chatMessageListener.listen({
+ callback: ({ data }) => {
+ console.log(data); // { message: string }
+ },
+});
+```
+
+---
+
+## Emitter templates
+
+To incorporate full type-safety and readability we also have emitter templates. They are used to send messages to the
+realtime servers. This way we keep very clear data-exchange between the client and the server. It is reusable and very
+easy to use.
+
+```tsx
+import { Socket } from "@hyper-fetch/sockets";
+
+// 1. Initialize the socket
+const socket = new Socket({
+ url: "ws://localhost:3000",
+});
+
+// 2. Create the emitter template
+const chatMessageEmitter = socket.createEmitter<{ text: string }>({
+ topic: "new-message",
+});
+
+// 3. Send the chat message
+chatMessageEmitter.emit({
+ data: { text: "Hello, world!" },
+});
+```
+
+---
+
+## Event-Driven and Extensible
+
+Sockets exposes all events, making it easy to build custom devtools, analytics, or advanced integrations. The
+event-driven approach ensures your app can react to every stage of the connection lifecycle.
+
+---
+
+## See More
+
+
+
+
+
+
+---
+
+With these building blocks, you're ready to build powerful, real-time features with **Hyper Fetch Sockets**! 🎊
diff --git a/documentation/docs/sockets/quick-start.mdx b/documentation/docs/sockets/quick-start.mdx
new file mode 100644
index 000000000..f342aec62
--- /dev/null
+++ b/documentation/docs/sockets/quick-start.mdx
@@ -0,0 +1,115 @@
+---
+sidebar_position: 2
+title: Quick Start
+sidebar_label: Quick Start
+---
+
+> Hyper Fetch's Sockets module enables real-time, bidirectional communication using WebSockets or other adapters. It's
+> framework-agnostic and requires no external libraries to function.
+
+:::secondary What you'll learn
+
+- How to initialize the socket client
+- How to create emitters and listeners
+- How to interact with the server
+
+:::
+
+---
+
+1. ### Initialize the Socket Client
+
+The first step is to initialize the **Socket client**. This manages the WebSocket connection and all real-time
+communication. Specify the `url` of your WebSocket server.
+
+```tsx title="socket.ts"
+import { Socket } from "@hyper-fetch/sockets";
+
+export const socket = new Socket({ url: "ws://localhost:3000" });
+```
+
+---
+
+2. ### Create Emitters and Listeners
+
+With your socket client set up, you can define **emitters** (to send events) and **listeners** (to receive events) for
+real-time communication.
+
+#### Creating Listeners
+
+Listeners subscribe to server events and provide type-safe callbacks.
+
+```ts
+import { socket } from "./socket";
+
+export const onChatMessage = socket.createListener()({
+ endpoint: "chat-message", // event name or endpoint
+});
+```
+
+#### Creating Emitters
+
+Emitters send events to the server, optionally handling acknowledgements.
+
+```tsx
+import { socket } from "./socket";
+
+export const sendChatMessage = socket.createEmitter()({
+ endpoint: "chat-message", // event name or endpoint
+});
+```
+
+:::tip
+
+Both listeners and emitters are fully typed, ensuring you always know the shape of your data.
+
+:::
+
+---
+
+3. ### Interact with the Server
+
+Once you have your emitters and listeners, you can send and receive real-time events.
+
+#### Listen to events
+
+Just use the `listen` method and pass the callback function.
+
+```ts
+import { onChatMessage } from "./listeners";
+
+onChatMessage.listen({ callback: (data) => console.log(data) });
+```
+
+#### Emit events
+
+Just use the `emit` method and pass the data you want to send.
+
+```ts
+import { sendChatMessage } from "./emitters";
+
+sendChatMessage.emit({ data: { message: "Hello world" } });
+```
+
+---
+
+## Additional: Changing the adapter
+
+By default, Sockets uses **WebSocket** adapter, but you can switch to SSE or provide your own adapter for maximum
+flexibility.
+
+```tsx
+import { ServerSentEventsAdapter } from "@hyper-fetch/sockets";
+
+socket.setAdapter(ServerSentEventsAdapter());
+```
+
+---
+
+:::success That's it!
+
+You've seen how straightforward it is to get started with Hyper Fetch Sockets for real-time communication.
+
+:::
+
+---
diff --git a/documentation/docs/sockets/socket.mdx b/documentation/docs/sockets/socket.mdx
new file mode 100644
index 000000000..693cee351
--- /dev/null
+++ b/documentation/docs/sockets/socket.mdx
@@ -0,0 +1,141 @@
+---
+sidebar_position: 3
+title: Socket
+sidebar_label: Socket
+---
+
+[Read the API Reference »](/api/sockets/Classes/Socket.mdx)
+
+**`Socket`** is the central class for configuring your server connection in the Hyper Fetch sockets module. It
+initializes all core subsystems—such as `offline`, `events`, and `interceptors`—and provides a unified way to create and
+manage listeners and emitters based on its configuration. By keeping all data and logic encapsulated within a single
+socket instance, you ensure that each socket remains isolated and independent from others.
+
+---
+
+:::tip Purpose
+
+1. **Orchestrates** the components and flow of the sockets library
+2. Creates **listeners** and **emitters** to provide global setup and environment
+3. Isolates sockets from each other and their events
+
+:::
+
+---
+
+## Initialization
+
+```tsx
+import { Socket } from "@hyper-fetch/sockets";
+
+export const socket = new Socket({ url: "ws://localhost:3000" });
+```
+
+---
+
+## Features
+
+Here are the main features of the `Socket` class.
+
+### Adapters
+
+You can pick between two built-in modes for the data exchange:
+
+1. **WebSocket mode** (default)
+2. **Server Sent Events (SSE) mode**
+
+You can change it with the `SSE` adapter:
+
+```tsx
+import { sseAdapter } from "@hyper-fetch/sockets";
+
+new Socket({ url: "ws://localhost:3000" }).setAdapter(sseAdapter);
+```
+
+---
+
+### Interceptors
+
+There are a few methods for intercepting a response from a request:
+
+- `onSend` — triggered before sending an event.
+
+```tsx
+new Socket({ url: "ws://localhost:3000" }).onSend((event) => {
+ // Modify the event before it is sent
+ event.payload = { ...event.payload, token: "1234567890" };
+ return event;
+});
+```
+
+- `onError` — triggered on error from socket.
+
+```tsx
+new Socket({ url: "ws://localhost:3000" }).onError((error) => {
+ // Modify the error before it is emitted to other sub-systems
+ error.message = "An error occurred";
+ return error;
+});
+```
+
+- `onMessage` — triggered on any received message.
+
+```tsx
+new Socket({ url: "ws://localhost:3000" }).onMessage((message) => {
+ // Modify the message before it is emitted to other sub-systems
+ message.data = { ...message.data, token: "1234567890" };
+ return message;
+});
+```
+
+You can modify received data or payload with these interceptors before it is emitted to other sub-systems.
+
+---
+
+### Query Params
+
+Sockets has a built-in query params encoding function; you can modify its options or provide your own function. Use the
+`queryParamsConfig` method and the options listed below.
+
+(@import core QueryStringifyOptionsType type=returns)
+
+To change the encoding function, use the `queryParamsStringify` method:
+
+```tsx
+export const socket = new Socket({
+ url: "ws://localhost:3000",
+ queryParams: { param1: [1, 2, 3], param2: "test" },
+ queryParamsStringify: (value: string) => encode(value),
+});
+```
+
+---
+
+### Authentication
+
+To exchange authenticated events, set up the `queryParams` parameter with authentication parameter.
+
+```tsx
+export const socket = new Socket({
+ url: "ws://localhost:3000",
+ queryParams: { authToken: "1234567890" },
+});
+```
+
+
+
+---
+
+## TypeScript
+
+Sockets has one generic type responsible for the type of the current `Socket Adapter`. It defaults to the built-in
+adapter type and **will automatically change** to any new adapter type you pass to the `Socket` class.
+
+---
+
+{/* ## See More */}
diff --git a/documentation/docusaurus.config.js b/documentation/docusaurus.config.js
deleted file mode 100644
index 66a7d8f0d..000000000
--- a/documentation/docusaurus.config.js
+++ /dev/null
@@ -1,293 +0,0 @@
-/* eslint-disable @typescript-eslint/no-var-requires */
-/* eslint-disable global-require */
-// @ts-check
-// Note: type annotations allow type checking and IDEs autocompletion
-
-const lightCodeTheme = require("prism-react-renderer/themes/github");
-const darkCodeTheme = require("prism-react-renderer/themes/dracula");
-const path = require("path");
-
-// eslint-disable-next-line @typescript-eslint/ban-ts-comment
-// @ts-ignore
-const docsVersions = require("./versions.json");
-
-const apiDocs = "api";
-const apiDocsDir = "docs/api";
-
-const getVersions = () => {
- const versionsCount = Number(docsVersions[0][0]) + 1;
- const versions = {};
-
- Array(versionsCount)
- .fill(0)
- .forEach((_, index) => {
- const version = index + 1;
-
- if (versionsCount === version) {
- versions.current = {
- label: `${version}.x.x`,
- path: "",
- };
- } else {
- versions[`${version}.x.x`] = {
- noIndex: true,
- };
- }
- });
-
- return versions;
-};
-
-/** @type {import('@docusaurus/types').Config} */
-const config = {
- title: "Hyper Fetch",
- tagline: "Framework for requesting and realtime connection",
- url: "https://hyperfetch.bettertyped.com",
- baseUrl: "/",
- onBrokenLinks: "throw",
- onBrokenMarkdownLinks: "warn",
- favicon: "img/favicon.ico",
- organizationName: "BetterTyped",
- projectName: "Hyper Fetch",
- trailingSlash: true,
-
- scripts: [
- {
- src: "https://survey.survicate.com/workspaces/9f3c2b1e74133251e55420aaadfaf50d/web_surveys.js",
- async: true,
- },
- ],
-
- plugins: [
- "docusaurus-plugin-sass",
- [
- "@docusaurus/plugin-content-docs",
- {
- id: "sources",
- path: "sources",
- routeBasePath: "sources",
- sidebarPath: require.resolve("./sidebars.js"),
- },
- ],
- [
- "@docusaurus/plugin-content-docs",
- {
- id: "examples",
- path: "examples",
- routeBasePath: "examples",
- sidebarPath: require.resolve("./sidebars.js"),
- },
- ],
- [
- "docusaurus-docgen",
- {
- id: apiDocs,
- outDir: `docs/api`,
- tsConfigPath: path.join(__dirname, "../tsconfig.base.json"),
- packages: [
- {
- logo: "/img/logo.svg",
- title: "Hyper Fetch",
- dir: path.join(__dirname, "../packages/core"),
- entryPath: "src/index.ts",
- },
- {
- logo: "/img/react.svg",
- title: "React",
- dir: path.join(__dirname, "../packages/react"),
- entryPath: "src/index.ts",
- },
- {
- logo: "/img/features/049-messenger.svg",
- title: "Sockets",
- dir: path.join(__dirname, "../packages/sockets"),
- entryPath: "src/index.ts",
- },
- {
- logo: "/img/features/firebase.png",
- title: "Firebase",
- dir: path.join(__dirname, "../packages/adapter-firebase"),
- entryPath: "src/index.ts",
- },
- {
- logo: "/img/features/axios.png",
- title: "Axios",
- dir: path.join(__dirname, "../packages/adapter-axios"),
- entryPath: "src/index.ts",
- },
- ],
- },
- ],
- ],
-
- presets: [
- [
- "@docusaurus/preset-classic",
- /** @type {import('@docusaurus/preset-classic').Options} */
- ({
- docs: {
- remarkPlugins: [
- require("mdx-mermaid"),
- require("docusaurus-docgen").docsImporter({
- packageRoute: apiDocs,
- apiDir: apiDocsDir,
- }),
- ],
- routeBasePath: "docs",
- sidebarPath: require.resolve("./sidebars.docs.js"),
- editUrl: "https://github.com/BetterTyped/hyper-fetch/tree/main/documentation",
- showLastUpdateAuthor: true,
- showLastUpdateTime: true,
- lastVersion: "current",
- versions: getVersions(),
- },
- blog: {
- showReadingTime: true,
- editUrl: "https://github.com/BetterTyped/hyper-fetch/tree/main/documentation",
- },
- theme: {
- customCss: require.resolve("./src/css/custom.css"),
- },
- }),
- ],
- ],
-
- themeConfig:
- /** @type {import('@docusaurus/preset-classic').ThemeConfig} */
- ({
- colorMode: {
- defaultMode: "dark",
- },
- algolia: {
- appId: "E1R95VA83S",
- apiKey: "aa20780883ad65342c73e9527130a725",
- indexName: "hyperfetch",
- },
- navbar: {
- logo: {
- alt: "Hyper Fetch",
- src: "img/brand/HF.svg",
- },
- items: [
- {
- type: "doc",
- docId: "documentation/getting-started/overview",
- position: "left",
- label: "Docs",
- activeBaseRegex: `/docs`,
- },
- {
- to: "/docs/guides/basic/setup/",
- label: "Guides",
- position: "left",
- activeBaseRegex: `/docs/guides/`,
- },
- {
- to: "/docs/api/",
- label: "API",
- position: "left",
- activeBaseRegex: `/docs/api`,
- },
- {
- to: "/examples/playground/",
- label: "Examples",
- position: "left",
- },
- {
- to: "/sources/overview/",
- label: "Sources",
- position: "left",
- activeBaseRegex: `/sources/`,
- },
- {
- to: "/blog/",
- label: "Blog",
- position: "left",
- },
- {
- type: "docsVersionDropdown",
- position: "right",
- },
- {
- href: "https://github.com/BetterTyped/hyper-fetch",
- label: "Github",
- position: "right",
- className: "github",
- },
- ],
- },
- footer: {
- style: "light",
- links: [
- {
- title: "Docs",
- items: [
- {
- label: "Getting Started",
- to: "/docs/documentation/getting-started/overview/",
- },
- {
- label: "Core",
- to: "/docs/documentation/core/client/",
- },
- {
- label: "React",
- to: "/docs/documentation/react/overview/",
- },
- ],
- },
- {
- title: "More",
- items: [
- {
- label: "Blog",
- to: "/blog",
- },
- {
- label: "BetterTyped",
- href: "https://bettertyped.com/docs/overview",
- },
- {
- label: "Stack Overflow",
- href: "https://stackoverflow.com/questions/tagged/hyper-fetch",
- },
- {
- label: "GitHub",
- href: "https://github.com/BetterTyped/hyper-fetch",
- },
- ],
- },
- {
- title: "Join Our Newsletter!",
- items: [
- {
- html: `
-
-
- `,
- },
- ],
- },
- ],
- copyright: `Copyright © ${new Date().getFullYear()} BetterTyped, Inc. Built with Docusaurus.`,
- },
- prism: {
- theme: lightCodeTheme,
- darkTheme: darkCodeTheme,
- },
- }),
-};
-
-module.exports = config;
diff --git a/documentation/docusaurus.config.ts b/documentation/docusaurus.config.ts
new file mode 100644
index 000000000..42e6b9521
--- /dev/null
+++ b/documentation/docusaurus.config.ts
@@ -0,0 +1,374 @@
+import type { Config } from "@docusaurus/types";
+import type * as Preset from "@docusaurus/preset-classic";
+import path from "path";
+import fs from "fs";
+import plugin from "@docsgen/docusaurus";
+import { importer } from "@docsgen/core";
+import { convertNpmToPackageManagers } from "@sapphire/docusaurus-plugin-npm2yarn2pnpm";
+
+import docsVersions from "./versions.json";
+
+const getVersions = () => {
+ const latestVersion = docsVersions[0] || "v0.0.0";
+ const latestMajor = latestVersion[1];
+ const currentVersion = Number(latestMajor) + 1;
+ const versions = { current: { label: `v${currentVersion}.0.0`, path: "" } };
+
+ [...Array(docsVersions.length)].fill(0).forEach((_, index) => {
+ const version = Number(latestMajor) - index;
+
+ if (currentVersion === version) {
+ versions.current = {
+ label: `v${version}.0.0`,
+ path: "",
+ };
+ } else {
+ versions[`v${version}.0.0`] = {
+ noIndex: true,
+ };
+ }
+ });
+
+ return versions;
+};
+
+const apiDocs = "api";
+const apiDocsDir = "docs/api";
+
+const getPackagesList = () => {
+ const dirPath = path.join(__dirname, "../packages");
+ const result: string[] = fs
+ .readdirSync(dirPath)
+ .filter((p) => ![".DS_Store", "hyper-flow", "testing"].includes(p))
+ .map((filePath) => {
+ return path.join(dirPath, filePath);
+ });
+
+ return result
+ .filter((item) => !item.includes("tokens"))
+ .map((dir) => {
+ const dirName = dir.split("/").pop();
+ const title = dirName[0] + dirName.slice(1);
+
+ return {
+ title,
+ dir,
+ entryPath: "src/index.ts",
+ tsconfigDir: dir,
+ };
+ });
+};
+
+/**
+ * *****
+ * Configs
+ * *****
+ */
+
+const config: Config = {
+ title: "HyperFetch",
+ tagline: "Take the HyperFetch.",
+ favicon: "img/favicon.ico",
+
+ // Set the production url of your site here
+ url: "https://hyperfetch.bettertyped.com/",
+ // Set the // pathname under which your site is served
+ // For GitHub pages deployment, it is often '//'
+ baseUrl: "/",
+
+ // GitHub pages deployment config.
+ // If you aren't using GitHub pages, you don't need these.
+ organizationName: "BetterTyped", // Usually your GitHub org/user name.
+ projectName: "HyperFetch", // Usually your repo name.
+
+ onBrokenLinks: "throw",
+ onBrokenMarkdownLinks: "warn",
+
+ future: {
+ v4: {
+ removeLegacyPostBuildHeadAttribute: true, // required
+ useCssCascadeLayers: false,
+ },
+ experimental_faster: {
+ rspackBundler: true,
+ rspackPersistentCache: true,
+ ssgWorkerThreads: true,
+ swcJsLoader: true,
+ swcJsMinimizer: true,
+ swcHtmlMinimizer: true,
+ lightningCssMinimizer: true,
+ mdxCrossCompilerCache: true,
+ },
+ },
+
+ // Even if you don't use internationalization, you can use this field to set
+ // useful metadata like html lang. For example, if your site is Chinese, you
+ // may want to replace "en" with "zh-Hans".
+ i18n: {
+ defaultLocale: "en",
+ locales: ["en"],
+ },
+
+ scripts: [
+ {
+ src: "/js/theme.js",
+ async: false,
+ },
+ ],
+
+ headTags: [
+ {
+ tagName: "link",
+ attributes: {
+ rel: "stylesheet",
+ href: "https://fonts.googleapis.com/css2?family=Figtree:wght@300;400;500;600;700;800;900&family=Inter:wght@100;200;300;400;500;600;700;800;900&display=swap",
+ },
+ },
+ ],
+
+ presets: [
+ [
+ "classic",
+ {
+ docs: {
+ lastVersion: "current",
+ versions: getVersions(),
+ sidebarCollapsible: false,
+ sidebarCollapsed: false,
+ sidebarPath: "./sidebars.ts",
+ editUrl: "https://github.com/BetterTyped/hyper-fetch/tree/main/documentation",
+ remarkPlugins: [
+ convertNpmToPackageManagers,
+ importer({
+ packageRoute: apiDocs,
+ apiDir: apiDocsDir,
+ }),
+ ],
+ },
+ blog: {
+ showReadingTime: true,
+ editUrl: "https://github.com/BetterTyped/hyper-fetch/tree/main/documentation",
+ },
+ theme: {
+ customCss: "./src/css/custom.css",
+ },
+ } satisfies Preset.Options,
+ ],
+ ],
+
+ plugins: [
+ "docusaurus-plugin-sass",
+ async function tailwindPlugin() {
+ return {
+ name: "docusaurus-tailwindcss",
+ configurePostCss(postcssOptions) {
+ // Appends TailwindCSS and AutoPrefixer.
+ // eslint-disable-next-line @typescript-eslint/no-var-requires, global-require
+ postcssOptions.plugins.push(require("tailwindcss"));
+ // eslint-disable-next-line @typescript-eslint/no-var-requires, global-require
+ postcssOptions.plugins.push(require("autoprefixer"));
+ return postcssOptions;
+ },
+ };
+ },
+ [
+ "@docusaurus/plugin-content-docs",
+ {
+ id: "examples",
+ path: "examples",
+ routeBasePath: "examples",
+ sidebarPath: require.resolve("./sidebars.examples.js"),
+ },
+ ],
+ [
+ "@docsgen/docusaurus",
+ {
+ id: apiDocs,
+ outDir: `docs/api`,
+ packages: getPackagesList(),
+ logLevel: "trace",
+ addMonorepoPage: false,
+ addPackagePage: false,
+ } satisfies Parameters[1],
+ ],
+ ],
+
+ themes: ["@docusaurus/theme-mermaid"],
+
+ // In order for Mermaid code blocks in Markdown to work,
+ // you also need to enable the Remark plugin with this option
+ markdown: {
+ mermaid: true,
+ },
+
+ themeConfig: {
+ // Replace with your project's social card
+ image: "img/logo.svg",
+ algolia: {
+ appId: "E1R95VA83S",
+ apiKey: "aa20780883ad65342c73e9527130a725",
+ indexName: "hyperfetch",
+ },
+ colorMode: {
+ defaultMode: "dark",
+ disableSwitch: true,
+ respectPrefersColorScheme: false,
+ },
+ liveCodeBlock: {
+ playgroundPosition: "bottom",
+ },
+ tableOfContents: {
+ minHeadingLevel: 2,
+ maxHeadingLevel: 3,
+ },
+ navbar: {
+ title: "",
+ logo: {
+ alt: "HyperFetch Logo",
+ src: "img/brand/HF.svg",
+ },
+ items: [
+ {
+ position: "left",
+ label: "Docs",
+ to: "/docs/getting-started",
+ activeBaseRegex: `^/docs((?!examples|integrations|guides|api).)*$`,
+ },
+ {
+ to: "/docs/integrations/getting-started",
+ position: "left",
+ label: "Integrations",
+ activeBaseRegex: `/docs/integrations/`,
+ },
+ {
+ to: "/docs/guides/getting-started",
+ position: "left",
+ label: "Guides",
+ activeBaseRegex: `/docs/guides/`,
+ },
+ {
+ to: "/docs/api/getting-started",
+ position: "left",
+ label: "Api",
+ activeBaseRegex: `/docs/api/`,
+ },
+ {
+ to: "/examples/playground/",
+ label: "Examples",
+ position: "left",
+ },
+ {
+ to: "/blog",
+ position: "left",
+ label: "Blog",
+ },
+ {
+ href: "https://github.com/BetterTyped/hyper-fetch",
+ label: "Github",
+ position: "right",
+ className: "github",
+ },
+ // {
+ // type: "docsVersionDropdown",
+ // position: "right",
+ // dropdownActiveClassDisabled: true,
+ // docsPluginId: "default",
+ // className: "nav_versioning",
+ // },
+ {
+ type: "custom-myButton",
+ to: "/docs/hyper-flow",
+ position: "right",
+ children: "Get Access to HyperFlow",
+ navbarIcon: true,
+ },
+ ],
+ },
+ footer: {
+ style: "dark",
+ links: [
+ {
+ title: "Docs",
+ items: [
+ {
+ label: "Documentation",
+ to: "/docs/getting-started",
+ },
+ ],
+ },
+ {
+ title: "Community",
+ items: [
+ {
+ label: "Stack Overflow",
+ href: "https://stackoverflow.com/questions/tagged/HyperFetch",
+ },
+ {
+ label: "Github",
+ href: "https://github.com/BetterTyped/hyper-fetch",
+ },
+ ],
+ },
+ {
+ title: "More",
+ items: [
+ {
+ label: "Blog",
+ to: "/blog",
+ },
+ ],
+ },
+ ],
+ copyright: `Copyright © ${new Date().getFullYear()} BetterTyped.`,
+ },
+ prism: {
+ magicComments: [
+ {
+ className: "code-block-diff-add-line",
+ line: "diff-add-next-line",
+ block: { start: "diff-add-start", end: "diff-add-end" },
+ },
+ {
+ className: "code-block-diff-remove-line",
+ line: "diff-remove-next-line",
+ block: { start: "diff-remove-start", end: "diff-remove-end" },
+ },
+ {
+ className: "theme-code-block-highlighted-line",
+ line: "highlight-next-line",
+ block: { start: "highlight-start", end: "highlight-end" },
+ },
+ {
+ className: "code-block-error-line",
+ line: "error-next-line",
+ block: { start: "error-start", end: "error-end" },
+ },
+ {
+ className: "code-block-code-editor-split",
+ line: "code-editor-split",
+ },
+ ],
+ theme: {
+ plain: {},
+ styles: [
+ {
+ types: ["constructor"],
+ style: { color: "rgb(255, 255, 255)" },
+ },
+ ],
+ },
+ darkTheme: {
+ plain: {},
+ styles: [
+ {
+ types: ["constructor"],
+ style: { color: "rgb(255, 255, 255)" },
+ },
+ ],
+ },
+ },
+ } satisfies Preset.ThemeConfig,
+};
+
+// eslint-disable-next-line import/no-default-export
+export default config;
diff --git a/documentation/global.d.ts b/documentation/global.d.ts
new file mode 100644
index 000000000..56f33e435
--- /dev/null
+++ b/documentation/global.d.ts
@@ -0,0 +1,17 @@
+declare module "*.png" {
+ const content: string;
+ // eslint-disable-next-line import/no-default-export
+ export default content;
+}
+
+declare module "*.webp" {
+ const content: string;
+ // eslint-disable-next-line import/no-default-export
+ export default content;
+}
+
+declare module "*.svg" {
+ const content: React.ComponentType>;
+ // eslint-disable-next-line import/no-default-export
+ export default content;
+}
diff --git a/documentation/package.json b/documentation/package.json
index b44999c3c..2db4179f6 100644
--- a/documentation/package.json
+++ b/documentation/package.json
@@ -4,8 +4,8 @@
"private": true,
"scripts": {
"docusaurus": "docusaurus",
- "start": "npx rimraf docs/api & docusaurus start",
- "build": "docusaurus build",
+ "start": "docusaurus clear && docusaurus start",
+ "build": "docusaurus clear && docusaurus build",
"swizzle": "docusaurus swizzle",
"deploy": "docusaurus deploy",
"clear": "docusaurus clear",
@@ -15,36 +15,62 @@
"typecheck": "tsc"
},
"dependencies": {
- "@docusaurus/core": "^2.2.0",
- "@docusaurus/preset-classic": "^2.2.0",
- "@hyper-fetch/core": "^3.0.1",
- "@hyper-fetch/react": "^3.0.1",
- "@mdx-js/react": "^1.6.21",
- "@svgr/webpack": "^5.5.0",
+ "@docsgen/core": "^1.2.6",
+ "@docsgen/docusaurus": "^1.2.6",
+ "@docusaurus/core": "^3.8.1",
+ "@docusaurus/faster": "^3.8.1",
+ "@docusaurus/preset-classic": "^3.8.1",
+ "@docusaurus/remark-plugin-npm2yarn": "^3.8.1",
+ "@docusaurus/theme-live-codeblock": "^3.8.1",
+ "@docusaurus/theme-mermaid": "^3.8.1",
+ "@hyper-fetch/core": "link:../node_modules/@hyper-fetch/core",
+ "@hyper-fetch/react": "link:../node_modules/@hyper-fetch/react",
+ "@mdx-js/react": "^3.0.0",
+ "@radix-ui/react-tabs": "^1.1.11",
+ "@radix-ui/react-toast": "^1.2.13",
+ "@react-theater/scroll": "^1.0.0",
+ "@react-three/drei": "^9.115.0",
+ "@react-three/fiber": "^8.17.10",
+ "@reins/hooks": "0.7.0",
+ "@reins/types": "0.7.0",
+ "@reins/utils": "0.7.0",
+ "@sapphire/docusaurus-plugin-npm2yarn2pnpm": "^2.0.2",
"@tippyjs/react": "^4.2.6",
- "cli-progress": "^3.11.1",
- "clsx": "^1.1.1",
- "docusaurus-docgen": "^1.2.1",
- "docusaurus-plugin-sass": "^0.2.2",
- "file-loader": "^6.2.0",
- "gsap": "2.1.3",
- "mdx-mermaid": "^1.2.3",
- "mermaid": "^8.13.8",
- "prism-react-renderer": "^1.3.3",
- "react": "^17.0.1",
- "react-countup": "^6.3.2",
- "react-dom": "^17.0.1",
- "sass": "^1.53.0",
- "semantic-release": "^19.0.5",
- "unified": "^10.1.1",
- "url-loader": "^4.1.1"
+ "autoprefixer": "^10.4.16",
+ "clsx": "^1.2.1",
+ "codehike": "^1.0.6",
+ "docusaurus-plugin-sass": "^0.2.5",
+ "events": "^3.3.0",
+ "gsap": "3.12.5",
+ "link": "^2.1.1",
+ "lucide-react": "^0.453.0",
+ "motion": "^12.9.4",
+ "postcss": "^8.4.31",
+ "prismjs": "^1.29.0",
+ "react": "link:../node_modules/react",
+ "react-dom": "link:../node_modules/react-dom",
+ "react-live": "4.1.8",
+ "react-slick": "^0.29.0",
+ "sass": "^1.80.5",
+ "slick-carousel": "^1.8.1",
+ "sonner": "^2.0.3",
+ "swiper": "^8.4.7",
+ "tailwindcss": "^3.3.5",
+ "three": "^0.170.0"
},
"devDependencies": {
- "@docusaurus/module-type-aliases": "^2.2.0",
- "@tsconfig/docusaurus": "^1.0.4",
- "@types/node": "^18.11.3",
- "rollup-plugin-delete": "^2.0.0",
- "typescript": "^4.3.5"
+ "@docusaurus/module-type-aliases": "^3.8.1",
+ "@docusaurus/tsconfig": "^3.8.1",
+ "@docusaurus/types": "^3.8.1",
+ "@types/prismjs": "^1.26.3",
+ "@types/react-slick": "^0.23.11",
+ "tslib": "^2.6.2",
+ "typescript": "~5.2.2"
+ },
+ "resolutions": {
+ "wrap-ansi": "7.0.0",
+ "string-width": "4.2.3",
+ "strip-ansi": "6.0.1"
},
"browserslist": {
"production": [
@@ -53,9 +79,12 @@
"not op_mini all"
],
"development": [
- "last 1 chrome version",
- "last 1 firefox version",
- "last 1 safari version"
+ "last 3 chrome version",
+ "last 3 firefox version",
+ "last 5 safari version"
]
+ },
+ "engines": {
+ "node": ">=18.0"
}
}
diff --git a/documentation/sidebars.docs.js b/documentation/sidebars.docs.js
deleted file mode 100644
index aa952bf06..000000000
--- a/documentation/sidebars.docs.js
+++ /dev/null
@@ -1,8 +0,0 @@
-/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */
-const sidebars = {
- docs: [{ type: "autogenerated", dirName: "documentation" }],
- api: [{ type: "autogenerated", dirName: "api" }],
- guides: [{ type: "autogenerated", dirName: "guides" }],
-};
-
-module.exports = sidebars;
diff --git a/documentation/sidebars.examples.ts b/documentation/sidebars.examples.ts
new file mode 100644
index 000000000..600d6b930
--- /dev/null
+++ b/documentation/sidebars.examples.ts
@@ -0,0 +1,19 @@
+import type { SidebarsConfig } from "@docusaurus/plugin-content-docs";
+
+/**
+ * Creating a sidebar enables you to:
+ - create an ordered group of docs
+ - render a sidebar for each doc of that group
+ - provide next/previous navigation
+
+ The sidebars can be generated from the filesystem, or explicitly defined here.
+
+ Create as many sidebars as you want.
+ */
+
+const sidebars: SidebarsConfig = {
+ sidebar: [{ type: "autogenerated", dirName: "." }],
+};
+
+// eslint-disable-next-line import/no-default-export
+export default sidebars;
diff --git a/documentation/sidebars.js b/documentation/sidebars.js
deleted file mode 100644
index 966215066..000000000
--- a/documentation/sidebars.js
+++ /dev/null
@@ -1,31 +0,0 @@
-/**
- * Creating a sidebar enables you to:
- - create an ordered group of docs
- - render a sidebar for each doc of that group
- - provide next/previous navigation
-
- The sidebars can be generated from the filesystem, or explicitly defined here.
-
- Create as many sidebars as you want.
- */
-
-// @ts-check
-
-/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */
-const sidebars = {
- // By default, Docusaurus generates a sidebar from the docs folder structure
- tutorialSidebar: [{ type: "autogenerated", dirName: "." }],
-
- // But you can create a sidebar manually
- /*
- tutorialSidebar: [
- {
- type: 'category',
- label: 'Tutorial',
- items: ['hello'],
- },
- ],
- */
-};
-
-module.exports = sidebars;
diff --git a/documentation/sidebars.ts b/documentation/sidebars.ts
new file mode 100644
index 000000000..7e2a98959
--- /dev/null
+++ b/documentation/sidebars.ts
@@ -0,0 +1,61 @@
+import type { SidebarsConfig } from "@docusaurus/plugin-content-docs";
+
+import { modules } from "./src/modules";
+import { integrations } from "./src/integrations";
+import { apiOverviewSection } from "./src/apis";
+import { guides } from "./src/guides";
+
+/**
+ * Creating a sidebar enables you to:
+ - create an ordered group of docs
+ - render a sidebar for each doc of that group
+ - provide next/previous navigation
+
+ The sidebars can be generated from the filesystem, or explicitly defined here.
+
+ Create as many sidebars as you want.
+ */
+
+// Detect duplicates in setup
+modules.some((section) => {
+ return integrations.some((plugin) => {
+ if (plugin.isPackage && section.dir === plugin.dir) {
+ throw new Error(`Detected duplicate section directories between integrations and modules: ${section.dir}`);
+ }
+ return false;
+ });
+});
+
+const sidebars: SidebarsConfig = {
+ // Docs
+ ...modules.reduce((acc, section) => {
+ acc[section.dir] = [{ type: "autogenerated", dirName: section.dir }];
+ return acc;
+ }, {}),
+ // Guides
+ ...guides.reduce((acc, section) => {
+ acc[`guides/${section.dir}`] = [{ type: "autogenerated", dirName: `guides/${section.dir}` }];
+ return acc;
+ }, {}),
+ // Integrations
+ ...integrations.reduce((acc, section) => {
+ acc[`integrations/${section.dir}`] = [{ type: "autogenerated", dirName: `integrations/${section.dir}` }];
+ return acc;
+ }, {}),
+ // API
+ ...[
+ apiOverviewSection,
+ ...modules.filter((section) => section.isPackage),
+ ...integrations.filter((section) => section.isPackage),
+ ].reduce((acc, section) => {
+ const dir = section.dir.includes("integrations")
+ ? section.dir.replace("integrations/", "api/")
+ : `api/${section.dir}`;
+
+ acc[dir] = [{ type: "autogenerated", dirName: dir }];
+ return acc;
+ }, {}),
+};
+
+// eslint-disable-next-line import/no-default-export
+export default sidebars;
diff --git a/documentation/sources/Contributing.mdx b/documentation/sources/Contributing.mdx
index 5eeca03cd..d56c40112 100644
--- a/documentation/sources/Contributing.mdx
+++ b/documentation/sources/Contributing.mdx
@@ -17,8 +17,6 @@ community looks forward to your contributions. 🎉
> - Refer this project in your project's readme
> - Mention the project at local meetups and tell your friends/colleagues
-
-
+- [Join The Project Team](#join-the-project-team)
## I Have a Question
@@ -48,10 +46,12 @@ If you then still feel the need to ask a question and need clarification, we rec
We will then take care of the issue as soon as possible.
-
## I Want To Contribute
-> ### Legal Notice
+> ### Legal Notice
>
> When contributing to this project, you must agree that you have authored 100% of the content, that you have the
> necessary rights to the content and that the content you contribute may be provided under the project license.
### Reporting Bugs
-
-
#### Before Submitting a Bug Report
A good bug report shouldn't leave others needing to chase you up for more information. Therefore, we ask you to
@@ -96,16 +93,14 @@ following steps in advance to help us fix any potential bug as fast as possible.
- Possibly your input and the output
- Can you reliably reproduce the issue? And can you also reproduce it with older versions?
-
-
#### How Do I Submit a Good Bug Report?
> You must never report security related issues, vulnerabilities or bugs including sensitive information to the issue
> tracker, or elsewhere in public.
-
+Instead sensitive bugs must be sent by email to .
-
+You may add a PGP key to allow the messages to be sent encrypted as well.
We use GitHub issues to track bugs and errors. If you run into an issue with the project:
@@ -126,7 +121,8 @@ Once it's filed:
- If the team is able to reproduce the issue, it will be marked `needs-fix`, as well as possibly other tags (such as
`critical`), and the issue will be left to be [implemented by someone](#your-first-code-contribution).
-
+You might want to create an issue template for bugs and errors that can be used as a guide and that defines the
+structure of the information to be included. If you do so, reference it here in the description.
### Suggesting Enhancements
@@ -134,7 +130,7 @@ This section guides you through submitting an enhancement suggestion for Hyper F
features and minor improvements to existing functionality**. Following these guidelines will help maintainers and the
community to understand your suggestion and find related suggestions.
-
+omit in toc
#### Before Submitting an Enhancement
@@ -148,7 +144,7 @@ community to understand your suggestion and find related suggestions.
useful to the majority of our users and not just a small subset. If you're just targeting a minority of users,
consider writing an add-on/plugin library.
-
+omit in toc
#### How Do I Submit a Good Enhancement Suggestion?
diff --git a/documentation/src/apis.ts b/documentation/src/apis.ts
new file mode 100644
index 000000000..2a9ecea49
--- /dev/null
+++ b/documentation/src/apis.ts
@@ -0,0 +1,21 @@
+import { Book } from "lucide-react";
+
+import { Section } from "./modules";
+
+export const apiOverviewSection: Section = {
+ label: "Getting Started",
+ description: "",
+ category: "Docs",
+ isPackage: false,
+ dir: "getting-started",
+ paths: ["getting-started"],
+ img: Book,
+ text: "drop-shadow-sm !text-orange-500 dark:!text-orange-400",
+ textAction: "focus:!text-orange-500 focus:dark:!text-orange-400 active:!text-orange-600 active:dark:!text-orange-300",
+ textHover: "hover:!text-orange-500 hover:dark:!text-orange-400",
+ icon: "group-hover:shadow-orange-200 dark:group-hover:bg-orange-500 bg-orange-400 dark:bg-orange-500",
+ iconHover:
+ "group-hover:shadow-orange-200 dark:group-hover:bg-orange-500 group-hover:bg-orange-400 group-hover:dark:bg-orange-500 group-hover:!bg-opacity-40",
+ border: "border-orange-500 dark:border-orange-400",
+ borderHover: "hover:border-orange-500 hover:dark:border-orange-400",
+};
diff --git a/documentation/src/components/badge/badge.module.css b/documentation/src/components/badge/badge.module.css
new file mode 100644
index 000000000..fbdc3ff2d
--- /dev/null
+++ b/documentation/src/components/badge/badge.module.css
@@ -0,0 +1,54 @@
+.badge {
+ @apply flex items-center shadow-gray-300 dark:shadow-gray-600 bg-zinc-900;
+ display: flex;
+ border-radius: 9999px;
+ position: relative;
+ overflow: hidden;
+ box-shadow: 0 1000px 0 0 var(--tw-shadow-color) inset;
+ transition: all 200ms ease-in-out;
+ background: transparent !important;
+ text-decoration: none !important;
+}
+
+.badge:hover {
+ transform: scale(1.05);
+}
+
+.badge::before {
+ content: "";
+ background: conic-gradient(
+ from 45deg at 50% 50%,
+ transparent,
+ transparent,
+ transparent,
+ transparent,
+ transparent,
+ orange,
+ transparent,
+ transparent,
+ transparent
+ );
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ width: 100%;
+ height: 100%;
+ animation: rotate 3s linear infinite;
+}
+
+.backdrop {
+ @apply dark:bg-zinc-900 bg-white;
+ position: absolute;
+ inset: 1px;
+ border-radius: 9999px;
+}
+
+@keyframes rotate {
+ 0% {
+ transform: translate(-50%, -50%) scale(1.4) rotate(0turn);
+ }
+ 100% {
+ transform: translate(-50%, -50%) scale(1.4) rotate(1turn);
+ }
+}
diff --git a/documentation/src/components/badge/badge.tsx b/documentation/src/components/badge/badge.tsx
new file mode 100644
index 000000000..1c508ffa9
--- /dev/null
+++ b/documentation/src/components/badge/badge.tsx
@@ -0,0 +1,17 @@
+import { HTMLProps } from "react";
+import clsx from "clsx";
+
+import styles from "./badge.module.css";
+
+export const Badge = ({
+ children,
+ as: Component = "span",
+ ...props
+}: { children: React.ReactNode; as: "a" | "span" } & Partial>) => {
+ return (
+
+
+ {children}
+
+ );
+};
diff --git a/documentation/src/components/creators/creators.module.css b/documentation/src/components/creators/creators.module.css
deleted file mode 100644
index f03569e1e..000000000
--- a/documentation/src/components/creators/creators.module.css
+++ /dev/null
@@ -1,63 +0,0 @@
-.container {
- margin: 0 0 80px;
- padding: 80px 0;
-}
-
-.row {
- display: grid;
- grid-template-columns: 1fr 1fr;
- gap: 40px;
- max-width: 500px;
- margin: auto;
-}
-
-.block {
- display: flex;
- flex-direction: column;
- align-items: center;
-}
-
-.image {
- display: flex;
- justify-content: center;
-}
-
-.image img {
- width: 120px;
- height: 120px;
- border-radius: 14px;
-}
-
-.title {
- text-align: center;
- font-size: 18px;
-}
-
-.description {
- font-size: 12px;
- text-align: center;
- margin: 0 auto;
-}
-
-@media (max-width: 992px) {
- .title {
- font-size: 16px;
- }
-
- .container {
- margin: 0 0 60px;
- padding: 40px 0;
- }
- .row {
- grid-template-columns: 1fr 1fr;
- }
-}
-@media (max-width: 325px) {
- .container {
- margin: 0 0 40px;
- padding: 40px 0;
- }
- .row {
- grid-template-columns: 1fr;
- }
-}
diff --git a/documentation/src/components/creators/creators.tsx b/documentation/src/components/creators/creators.tsx
deleted file mode 100644
index 224c57d84..000000000
--- a/documentation/src/components/creators/creators.tsx
+++ /dev/null
@@ -1,57 +0,0 @@
-import React from "react";
-import clsx from "clsx";
-
-import styles from "./creators.module.css";
-
-export function Creators(): JSX.Element {
- return (
-
- );
-}
diff --git a/documentation/src/components/description/description.module.css b/documentation/src/components/description/description.module.css
deleted file mode 100644
index 787f1e3dd..000000000
--- a/documentation/src/components/description/description.module.css
+++ /dev/null
@@ -1,87 +0,0 @@
-.container {
- padding: 100px 20px 100px;
- background: #dfdfdf;
- border-top: 1px solid var(--ifm-color-secondary-dark);
- border-bottom: 1px solid var(--ifm-color-secondary-dark);
- background-image: radial-gradient(var(--ifm-color-emphasis-500) 1px, transparent 1px),
- radial-gradient(var(--ifm-color-emphasis-500) 1px, transparent 1px);
- background-position: 0 0, 60px 60px;
- background-size: 30px 30px;
-}
-
-html[data-theme="dark"] .container {
- background-color: var(--section-background);
- border-top: 1px solid var(--ifm-toc-border-color);
- border-bottom: 1px solid var(--ifm-toc-border-color);
- background-image: radial-gradient(rgba(0, 0, 0, 0.05), 1.3px, transparent 1.3px),
- radial-gradient(rgba(0, 0, 0, 0.05), 1.3px, transparent 1.3px);
-}
-
-.row {
- display: grid;
- grid-template-columns: 1fr 1fr 1fr;
- gap: 50px 60px;
- margin-top: 80px;
-}
-
-.imageWrapper {
- display: flex;
- justify-content: center;
- align-items: center;
- padding: 14px;
- border-radius: 4px;
- background: var(--ifm-color-emphasis-100);
- width: fit-content;
- margin-bottom: 20px;
-}
-
-.featureSvg {
- width: 30px;
- height: 30px;
-}
-
-.title {
- white-space: nowrap;
-}
-
-/* .title:after {
- display: block;
- content: "";
- margin-top: 10px;
- width: 80px;
- height: 2px;
- background: var(--ifm-color-primary);
-} */
-
-.description {
- font-size: 1rem;
- color: var(--ifm-color-emphasis-700);
- opacity: 0.95;
- font-weight: 500;
-}
-html[data-theme="dark"] .description {
- color: var(--ifm-color-emphasis-400);
-}
-
-.link {
- margin-top: 100px;
- text-align: center;
-}
-
-@media (max-width: 992px) {
- .title {
- white-space: unset;
- }
- .row {
- grid-template-columns: 1fr;
- }
-}
-
-@media (max-width: 650px) {
- .title {
- font-size: 1.2em;
- }
- .description {
- font-size: 1em;
- }
-}
diff --git a/documentation/src/components/description/description.tsx b/documentation/src/components/description/description.tsx
index f6067663f..c95743e2a 100644
--- a/documentation/src/components/description/description.tsx
+++ b/documentation/src/components/description/description.tsx
@@ -1,77 +1,15 @@
-import React from "react";
-import clsx from "clsx";
-import Link from "@docusaurus/Link";
+export const Description = (
+ props: Omit, "size"> & { size?: "none" | "default" | "md" },
+) => {
+ const { className = "", size = "default" } = props;
-import styles from "./description.module.css";
+ const sizeClass = {
+ none: "",
+ md: "text-lg",
+ default: "text-sm md:text-lg lg:text-xl",
+ }[size];
-export function Description(): JSX.Element {
return (
-
-
-
No more architecture struggles.
-
- We offer an e2e solution that provides unified data flow and full integration with external solutions. Hyper
- Fetch solves your data management or requesting problems and offers solutions for writing effective tests and
- maintenance.
-
-
-
-
-
-
-
Full type safety
-
- Make changes and iterate with confidence by taking full advantage of TypeScript.
-
-
-
-
-
-
-
Realtime connection
-
- Get easy integration between queries and an open communication channel.
-
-
-
-
-
-
-
Easy progress tracking
-
- Preview each request and access upload and download status in a fabulously simple way.
-
-
-
-
-
-
-
Adaptable by design
-
Support all formats, requirements, and protocols.
-
-
-
-
-
-
Offline first and persistent
-
- Deliver a top-notch experience to your users regardless of their connection status.
-
-
-
-
-
-
-
Great DX
-
- Hyper Fetch’s outstanding autocomplete capabilities walk you through the process.
-
-
-
-
-
- Find more details in Architecture Docs
-
-
+
);
-}
+};
diff --git a/documentation/src/components/description/index.ts b/documentation/src/components/description/index.ts
new file mode 100644
index 000000000..47ba7add1
--- /dev/null
+++ b/documentation/src/components/description/index.ts
@@ -0,0 +1 @@
+export * from "./description";
diff --git a/documentation/src/components/fade-in/fade-in.tsx b/documentation/src/components/fade-in/fade-in.tsx
new file mode 100644
index 000000000..a768c99a0
--- /dev/null
+++ b/documentation/src/components/fade-in/fade-in.tsx
@@ -0,0 +1,71 @@
+import React from "react";
+import { useActors, useMakeup, Stage, StyleOptions } from "@react-theater/scroll";
+
+const FadeInContent = ({
+ children,
+ start = 0.05,
+ end = 0.25,
+ translateY = 50,
+ setActorStyle,
+}: {
+ children: React.ReactNode;
+ start?: number;
+ end?: number;
+ translateY?: number;
+ setActorStyle: (style: StyleOptions) => void;
+}) => {
+ // Change
+ useActors([
+ {
+ start: 0,
+ end: start,
+ screen: true,
+ onUpdate: () => {
+ setActorStyle({
+ opacity: 0,
+ });
+ },
+ },
+ {
+ start,
+ end,
+ screen: true,
+ onUpdate: ({ progress }) => {
+ setActorStyle({
+ opacity: progress,
+ translateY: `${translateY - translateY * progress}px`,
+ });
+ },
+ },
+ ]);
+
+ return children;
+};
+
+export const FadeIn = ({
+ children,
+ start,
+ end,
+ translateY,
+ className,
+ isStage = true,
+ ...rest
+}: {
+ children: React.ReactNode;
+ start?: number;
+ end?: number;
+ translateY?: number;
+ isStage?: boolean;
+} & React.HTMLProps) => {
+ const [actorRef, setActorStyle] = useMakeup();
+
+ const Component = isStage ? Stage : "div";
+
+ return (
+
+
+ {children}
+
+
+ );
+};
diff --git a/documentation/src/components/fade-in/index.ts b/documentation/src/components/fade-in/index.ts
new file mode 100644
index 000000000..443786d92
--- /dev/null
+++ b/documentation/src/components/fade-in/index.ts
@@ -0,0 +1 @@
+export * from "./fade-in";
diff --git a/documentation/src/components/features/features.module.css b/documentation/src/components/features/features.module.css
deleted file mode 100644
index 1a033e3b9..000000000
--- a/documentation/src/components/features/features.module.css
+++ /dev/null
@@ -1,117 +0,0 @@
-.features {
- position: relative;
- padding: 70px 0 100px;
-}
-
-.features::after {
- display: block;
- content: "";
- position: absolute;
- width: 100%;
- height: 200px;
- background-image: linear-gradient(var(--ifm-color-emphasis-500), var(--ifm-background-color));
- top: 0%;
- left: 0;
- z-index: -1;
- opacity: 0.3;
-}
-
-html[data-theme="dark"] .features::after {
- background-image: linear-gradient(var(--ifm-color-emphasis-200), var(--ifm-background-color));
-}
-
-.list {
- display: grid;
- gap: 20px 80px;
- grid-template-columns: 1fr 1fr 1fr;
-}
-
-.feature {
- display: grid;
- gap: 20px;
- grid-template-columns: auto 1fr;
-}
-
-.feature > * {
- margin: 0;
-}
-
-.imgWrapper {
- position: relative;
- margin-top: 6px;
- border-radius: 100%;
- overflow: hidden !important;
- display: flex;
- width: fit-content;
- height: fit-content;
-}
-
-.img {
- width: 25px;
- fill: var(--ifm-color-warning-light);
- margin: -3px;
-}
-
-.details {
- padding: 5px 0;
- line-height: 1.3;
-}
-
-.details a {
- font-size: 0.8em;
-}
-
-.description {
- flex: 1 1 auto;
- font-family: "Viga", sans-serif;
-}
-
-.link {
- margin-top: 100px;
- text-align: center;
-}
-
-@media (max-width: 1200px) {
- .list {
- grid-template-columns: 1fr 1fr;
- }
-}
-
-@media (max-width: 768px) {
- .list {
- gap: 30px 40px;
- grid-template-columns: 1fr 1fr;
- }
-}
-
-@media (max-width: 650px) {
- .list {
- gap: 30px;
- grid-template-columns: 1fr;
- }
-}
-
-@media (max-width: 500px) {
- .description {
- font-size: 0.8em;
- }
- .details a {
- font-size: 0.7em;
- }
-
- .list {
- gap: 20px;
- grid-template-columns: 1fr;
- }
-
- .imageWrapper {
- padding: 10px;
- border-radius: 4px;
- background: var(--ifm-color-emphasis-100);
- height: 50px;
- }
- .featureSvg {
- width: 30px;
- height: 30px;
- }
-}
diff --git a/documentation/src/components/features/features.tsx b/documentation/src/components/features/features.tsx
deleted file mode 100644
index f082b7f67..000000000
--- a/documentation/src/components/features/features.tsx
+++ /dev/null
@@ -1,173 +0,0 @@
-/**
- * Copyright (c) Facebook, Inc. and its affiliates.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-import React, { useEffect } from "react";
-import clsx from "clsx";
-import Link from "@docusaurus/Link";
-import { TimelineMax, Back } from "gsap";
-
-import styles from "./features.module.css";
-import "./animation.scss";
-
-type FeatureItem = {
- description: string;
- // eslint-disable-next-line react/require-default-props
- link?: JSX.Element;
-};
-
-const FeatureList: FeatureItem[] = [
- {
- description: "Simple setup",
- link: Read more,
- },
- {
- description: "Automatic caching",
- link: Read more,
- },
- {
- description: "Built-in adapter",
- link: Read more,
- },
- {
- description: "Request cancellation",
- link: Read more,
- },
- {
- description: "Persistence",
- link: Read more,
- },
- {
- description: "Easy to test",
- link: Read more,
- },
- {
- description: "Window Focus/Blur Events",
- link: Read more,
- },
- {
- description: "SSR Support",
- link: Read more,
- },
- {
- description: "Authentication",
- link: Read more,
- },
- {
- description: "Queueing",
- link: Read more,
- },
- {
- description: "Offline first ready",
- link: Read more,
- },
- {
- description: "Prefetching",
- link: Read more,
- },
-];
-
-function Feature({ description, link }: FeatureItem) {
- return (
-
-
-
-
{description}
- {link}
-
-
- );
-}
-
-export function Features(): JSX.Element {
- useEffect(() => {
- const bolt = document.querySelector(".bolt");
- const element = bolt.querySelector("div");
-
- const animation = new TimelineMax({
- onStart() {
- bolt.classList.add("animate");
- },
- onComplete() {
- bolt.classList.remove("animate");
- setTimeout(() => {
- animation.restart();
- }, 1000);
- },
- })
- .set(element, {
- rotation: 360,
- })
- .to(element, 0.7, {
- y: 80,
- rotation: 370,
- })
- .to(element, 0.6, {
- y: -140,
- rotation: 20,
- })
- .to(element, 0.1, {
- rotation: -24,
- y: 80,
- })
- .to(element, 0.8, {
- ease: Back.easeOut.config(1.6),
- rotation: 0,
- y: 0,
- });
- }, []);
-
- return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
The future is now. Your Must-Have features are here.
-
- We provide a full range of functionalities, interfaces and possibilities so you can create solutions tailored
- to your needs. Easily connect to the events that power our architecture and confidently create your own logic.
- Hyper Fetch gives you full control over your data flow like no other framework can.
-
-
- {FeatureList.map((props, idx) => (
- // eslint-disable-next-line react/no-array-index-key, react/jsx-props-no-spreading
-
- ))}
-
-
-
- You can find more details in Comparison
-
-
- );
-}
diff --git a/documentation/src/components/header/animation.scss b/documentation/src/components/header/animation.scss
deleted file mode 100644
index 1a940768e..000000000
--- a/documentation/src/components/header/animation.scss
+++ /dev/null
@@ -1,1428 +0,0 @@
-.fireflies {
- position: absolute;
- top: 0;
- bottom: 0;
- left: 0;
- right: 0;
- z-index: -1;
-}
-
-.firefly {
- position: absolute;
- left: 50%;
- top: 50%;
- width: 0.4vw;
- height: 0.4vw;
- margin: -0.2vw 0 0 9.8vw;
- animation: ease 200s alternate infinite;
- pointer-events: none;
-}
-
-.firefly::before,
-.firefly::after {
- content: "";
- position: absolute;
- width: 100%;
- height: 100%;
- border-radius: 50%;
- transform-origin: -10vw;
-}
-
-.firefly::before {
- background: var(--ifm-color-emphasis-600);
- opacity: 0.4;
- animation: drift ease alternate infinite;
-}
-
-html[data-theme="dark"] .firefly::before {
- background: var(--ifm-color-emphasis-300);
-}
-
-.firefly::after {
- background: var(--ifm-color-warning-lightest);
- opacity: 0;
- box-shadow: 0 0 0vw 0vw var(--ifm-color-warning-light);
- animation: drift ease alternate infinite, flash ease infinite;
-}
-html[data-theme="dark"] .firefly::after {
- background: var(--ifm-color-warning-lightest);
- box-shadow: 0 0 0vw 0vw var(--ifm-color-warning-light);
-}
-
-.firefly:nth-child(1) {
- animation-name: move1;
-}
-
-.firefly:nth-child(1)::before {
- animation-duration: 10s;
-}
-
-.firefly:nth-child(1)::after {
- animation-duration: 10s, 8079ms;
- animation-delay: 0ms, 8183ms;
-}
-
-@keyframes move1 {
- 0% {
- transform: translateX(-1vw) translateY(-14vh) scale(0.66);
- }
- 3.7037% {
- transform: translateX(25vw) translateY(4vh) scale(0.96);
- }
- 7.40741% {
- transform: translateX(-41vw) translateY(-18vh) scale(0.79);
- }
- 11.11111% {
- transform: translateX(-42vw) translateY(27vh) scale(0.59);
- }
- 14.81481% {
- transform: translateX(7vw) translateY(37vh) scale(0.83);
- }
- 18.51852% {
- transform: translateX(-16vw) translateY(-15vh) scale(0.48);
- }
- 22.22222% {
- transform: translateX(16vw) translateY(39vh) scale(0.88);
- }
- 25.92593% {
- transform: translateX(-48vw) translateY(-3vh) scale(0.67);
- }
- 29.62963% {
- transform: translateX(41vw) translateY(6vh) scale(0.94);
- }
- 33.33333% {
- transform: translateX(-43vw) translateY(14vh) scale(0.6);
- }
- 37.03704% {
- transform: translateX(29vw) translateY(14vh) scale(0.64);
- }
- 40.74074% {
- transform: translateX(2vw) translateY(-39vh) scale(0.38);
- }
- 44.44444% {
- transform: translateX(-3vw) translateY(19vh) scale(0.27);
- }
- 48.14815% {
- transform: translateX(43vw) translateY(-12vh) scale(0.78);
- }
- 51.85185% {
- transform: translateX(-17vw) translateY(13vh) scale(0.84);
- }
- 55.55556% {
- transform: translateX(-47vw) translateY(-38vh) scale(0.88);
- }
- 59.25926% {
- transform: translateX(50vw) translateY(-44vh) scale(0.66);
- }
- 62.96296% {
- transform: translateX(45vw) translateY(42vh) scale(0.78);
- }
- 66.66667% {
- transform: translateX(23vw) translateY(42vh) scale(0.28);
- }
- 70.37037% {
- transform: translateX(-49vw) translateY(12vh) scale(0.65);
- }
- 74.07407% {
- transform: translateX(37vw) translateY(39vh) scale(0.96);
- }
- 77.77778% {
- transform: translateX(43vw) translateY(24vh) scale(0.38);
- }
- 81.48148% {
- transform: translateX(14vw) translateY(18vh) scale(0.86);
- }
- 85.18519% {
- transform: translateX(-8vw) translateY(-28vh) scale(0.68);
- }
- 88.88889% {
- transform: translateX(24vw) translateY(42vh) scale(0.54);
- }
- 92.59259% {
- transform: translateX(24vw) translateY(3vh) scale(0.51);
- }
- 96.2963% {
- transform: translateX(8vw) translateY(5vh) scale(0.27);
- }
- 100% {
- transform: translateX(32vw) translateY(23vh) scale(0.93);
- }
-}
-
-.firefly:nth-child(2) {
- animation-name: move2;
-}
-
-.firefly:nth-child(2)::before {
- animation-duration: 18s;
-}
-
-.firefly:nth-child(2)::after {
- animation-duration: 18s, 7995ms;
- animation-delay: 0ms, 3159ms;
-}
-
-@keyframes move2 {
- 0% {
- transform: translateX(-26vw) translateY(34vh) scale(0.35);
- }
- 5% {
- transform: translateX(42vw) translateY(42vh) scale(0.96);
- }
- 10% {
- transform: translateX(10vw) translateY(40vh) scale(0.41);
- }
- 15% {
- transform: translateX(0vw) translateY(-34vh) scale(0.56);
- }
- 20% {
- transform: translateX(1vw) translateY(-1vh) scale(0.55);
- }
- 25% {
- transform: translateX(-15vw) translateY(-26vh) scale(0.45);
- }
- 30% {
- transform: translateX(-26vw) translateY(47vh) scale(0.46);
- }
- 35% {
- transform: translateX(-7vw) translateY(29vh) scale(0.91);
- }
- 40% {
- transform: translateX(3vw) translateY(19vh) scale(0.98);
- }
- 45% {
- transform: translateX(-41vw) translateY(-14vh) scale(0.5);
- }
- 50% {
- transform: translateX(-39vw) translateY(-5vh) scale(0.52);
- }
- 55% {
- transform: translateX(-1vw) translateY(-30vh) scale(0.41);
- }
- 60% {
- transform: translateX(-11vw) translateY(10vh) scale(0.32);
- }
- 65% {
- transform: translateX(48vw) translateY(-17vh) scale(0.33);
- }
- 70% {
- transform: translateX(10vw) translateY(-10vh) scale(0.74);
- }
- 75% {
- transform: translateX(-40vw) translateY(-24vh) scale(0.75);
- }
- 80% {
- transform: translateX(37vw) translateY(45vh) scale(0.87);
- }
- 85% {
- transform: translateX(-19vw) translateY(30vh) scale(0.29);
- }
- 90% {
- transform: translateX(23vw) translateY(29vh) scale(0.62);
- }
- 95% {
- transform: translateX(42vw) translateY(-41vh) scale(0.96);
- }
- 100% {
- transform: translateX(-3vw) translateY(13vh) scale(0.78);
- }
-}
-
-.firefly:nth-child(3) {
- animation-name: move3;
-}
-
-.firefly:nth-child(3)::before {
- animation-duration: 12s;
-}
-
-.firefly:nth-child(3)::after {
- animation-duration: 12s, 6061ms;
- animation-delay: 0ms, 7833ms;
-}
-
-@keyframes move3 {
- 0% {
- transform: translateX(23vw) translateY(43vh) scale(0.68);
- }
- 3.7037% {
- transform: translateX(-10vw) translateY(-3vh) scale(1);
- }
- 7.40741% {
- transform: translateX(49vw) translateY(-22vh) scale(0.41);
- }
- 11.11111% {
- transform: translateX(13vw) translateY(-27vh) scale(0.69);
- }
- 14.81481% {
- transform: translateX(-33vw) translateY(29vh) scale(0.6);
- }
- 18.51852% {
- transform: translateX(-13vw) translateY(-24vh) scale(0.46);
- }
- 22.22222% {
- transform: translateX(43vw) translateY(-19vh) scale(0.27);
- }
- 25.92593% {
- transform: translateX(26vw) translateY(-48vh) scale(0.75);
- }
- 29.62963% {
- transform: translateX(12vw) translateY(20vh) scale(0.85);
- }
- 33.33333% {
- transform: translateX(49vw) translateY(-35vh) scale(0.42);
- }
- 37.03704% {
- transform: translateX(-15vw) translateY(42vh) scale(0.49);
- }
- 40.74074% {
- transform: translateX(-22vw) translateY(8vh) scale(0.67);
- }
- 44.44444% {
- transform: translateX(-14vw) translateY(-11vh) scale(0.77);
- }
- 48.14815% {
- transform: translateX(4vw) translateY(-13vh) scale(0.98);
- }
- 51.85185% {
- transform: translateX(-23vw) translateY(41vh) scale(0.59);
- }
- 55.55556% {
- transform: translateX(13vw) translateY(32vh) scale(0.64);
- }
- 59.25926% {
- transform: translateX(-6vw) translateY(19vh) scale(0.29);
- }
- 62.96296% {
- transform: translateX(-32vw) translateY(-44vh) scale(0.98);
- }
- 66.66667% {
- transform: translateX(37vw) translateY(40vh) scale(0.53);
- }
- 70.37037% {
- transform: translateX(-41vw) translateY(20vh) scale(0.39);
- }
- 74.07407% {
- transform: translateX(47vw) translateY(-20vh) scale(0.5);
- }
- 77.77778% {
- transform: translateX(33vw) translateY(-32vh) scale(0.58);
- }
- 81.48148% {
- transform: translateX(26vw) translateY(35vh) scale(0.95);
- }
- 85.18519% {
- transform: translateX(17vw) translateY(-1vh) scale(0.53);
- }
- 88.88889% {
- transform: translateX(-4vw) translateY(-2vh) scale(0.41);
- }
- 92.59259% {
- transform: translateX(-17vw) translateY(9vh) scale(0.8);
- }
- 96.2963% {
- transform: translateX(4vw) translateY(-37vh) scale(0.48);
- }
- 100% {
- transform: translateX(-39vw) translateY(26vh) scale(0.75);
- }
-}
-
-.firefly:nth-child(4) {
- animation-name: move4;
-}
-
-.firefly:nth-child(4)::before {
- animation-duration: 9s;
-}
-
-.firefly:nth-child(4)::after {
- animation-duration: 9s, 6550ms;
- animation-delay: 0ms, 5528ms;
-}
-
-@keyframes move4 {
- 0% {
- transform: translateX(-8vw) translateY(37vh) scale(0.4);
- }
- 3.84615% {
- transform: translateX(-44vw) translateY(45vh) scale(0.91);
- }
- 7.69231% {
- transform: translateX(26vw) translateY(48vh) scale(0.31);
- }
- 11.53846% {
- transform: translateX(37vw) translateY(23vh) scale(0.35);
- }
- 15.38462% {
- transform: translateX(1vw) translateY(40vh) scale(0.29);
- }
- 19.23077% {
- transform: translateX(-33vw) translateY(20vh) scale(0.49);
- }
- 23.07692% {
- transform: translateX(-31vw) translateY(28vh) scale(0.56);
- }
- 26.92308% {
- transform: translateX(-14vw) translateY(6vh) scale(0.33);
- }
- 30.76923% {
- transform: translateX(10vw) translateY(2vh) scale(0.65);
- }
- 34.61538% {
- transform: translateX(-10vw) translateY(-4vh) scale(0.28);
- }
- 38.46154% {
- transform: translateX(30vw) translateY(-3vh) scale(0.32);
- }
- 42.30769% {
- transform: translateX(50vw) translateY(-46vh) scale(0.48);
- }
- 46.15385% {
- transform: translateX(-38vw) translateY(8vh) scale(0.26);
- }
- 50% {
- transform: translateX(-25vw) translateY(-29vh) scale(0.92);
- }
- 53.84615% {
- transform: translateX(45vw) translateY(-26vh) scale(0.93);
- }
- 57.69231% {
- transform: translateX(3vw) translateY(-36vh) scale(0.67);
- }
- 61.53846% {
- transform: translateX(3vw) translateY(-35vh) scale(0.56);
- }
- 65.38462% {
- transform: translateX(-23vw) translateY(-9vh) scale(0.65);
- }
- 69.23077% {
- transform: translateX(-18vw) translateY(-18vh) scale(0.37);
- }
- 73.07692% {
- transform: translateX(-26vw) translateY(-14vh) scale(0.4);
- }
- 76.92308% {
- transform: translateX(-3vw) translateY(9vh) scale(0.55);
- }
- 80.76923% {
- transform: translateX(34vw) translateY(-24vh) scale(0.29);
- }
- 84.61538% {
- transform: translateX(-33vw) translateY(2vh) scale(0.62);
- }
- 88.46154% {
- transform: translateX(-32vw) translateY(-14vh) scale(0.82);
- }
- 92.30769% {
- transform: translateX(7vw) translateY(24vh) scale(0.98);
- }
- 96.15385% {
- transform: translateX(-36vw) translateY(21vh) scale(1);
- }
- 100% {
- transform: translateX(3vw) translateY(10vh) scale(0.87);
- }
-}
-
-.firefly:nth-child(5) {
- animation-name: move5;
-}
-
-.firefly:nth-child(5)::before {
- animation-duration: 9s;
-}
-
-.firefly:nth-child(5)::after {
- animation-duration: 9s, 8303ms;
- animation-delay: 0ms, 7967ms;
-}
-
-@keyframes move5 {
- 0% {
- transform: translateX(-10vw) translateY(-41vh) scale(0.66);
- }
- 4% {
- transform: translateX(28vw) translateY(4vh) scale(0.97);
- }
- 8% {
- transform: translateX(4vw) translateY(14vh) scale(0.9);
- }
- 12% {
- transform: translateX(8vw) translateY(32vh) scale(0.79);
- }
- 16% {
- transform: translateX(33vw) translateY(-2vh) scale(0.48);
- }
- 20% {
- transform: translateX(6vw) translateY(-14vh) scale(0.71);
- }
- 24% {
- transform: translateX(-39vw) translateY(31vh) scale(0.6);
- }
- 28% {
- transform: translateX(30vw) translateY(12vh) scale(0.4);
- }
- 32% {
- transform: translateX(44vw) translateY(-19vh) scale(0.35);
- }
- 36% {
- transform: translateX(19vw) translateY(41vh) scale(0.88);
- }
- 40% {
- transform: translateX(-22vw) translateY(-8vh) scale(0.81);
- }
- 44% {
- transform: translateX(-8vw) translateY(12vh) scale(1);
- }
- 48% {
- transform: translateX(-34vw) translateY(25vh) scale(0.29);
- }
- 52% {
- transform: translateX(20vw) translateY(-8vh) scale(0.7);
- }
- 56% {
- transform: translateX(-47vw) translateY(-49vh) scale(0.92);
- }
- 60% {
- transform: translateX(-29vw) translateY(-25vh) scale(0.93);
- }
- 64% {
- transform: translateX(-35vw) translateY(-27vh) scale(0.46);
- }
- 68% {
- transform: translateX(-43vw) translateY(-21vh) scale(0.67);
- }
- 72% {
- transform: translateX(8vw) translateY(-10vh) scale(0.46);
- }
- 76% {
- transform: translateX(-32vw) translateY(-41vh) scale(0.34);
- }
- 80% {
- transform: translateX(18vw) translateY(-3vh) scale(0.47);
- }
- 84% {
- transform: translateX(-45vw) translateY(47vh) scale(0.93);
- }
- 88% {
- transform: translateX(-32vw) translateY(-1vh) scale(0.29);
- }
- 92% {
- transform: translateX(-10vw) translateY(-26vh) scale(0.33);
- }
- 96% {
- transform: translateX(-24vw) translateY(24vh) scale(0.51);
- }
- 100% {
- transform: translateX(49vw) translateY(-27vh) scale(0.36);
- }
-}
-
-.firefly:nth-child(6) {
- animation-name: move6;
-}
-
-.firefly:nth-child(6)::before {
- animation-duration: 13s;
-}
-
-.firefly:nth-child(6)::after {
- animation-duration: 13s, 6594ms;
- animation-delay: 0ms, 8196ms;
-}
-
-@keyframes move6 {
- 0% {
- transform: translateX(-33vw) translateY(50vh) scale(0.47);
- }
- 3.7037% {
- transform: translateX(46vw) translateY(19vh) scale(0.38);
- }
- 7.40741% {
- transform: translateX(-41vw) translateY(-4vh) scale(0.27);
- }
- 11.11111% {
- transform: translateX(-47vw) translateY(38vh) scale(0.88);
- }
- 14.81481% {
- transform: translateX(11vw) translateY(46vh) scale(0.52);
- }
- 18.51852% {
- transform: translateX(-35vw) translateY(18vh) scale(0.97);
- }
- 22.22222% {
- transform: translateX(-14vw) translateY(-38vh) scale(0.48);
- }
- 25.92593% {
- transform: translateX(-26vw) translateY(-17vh) scale(0.72);
- }
- 29.62963% {
- transform: translateX(20vw) translateY(31vh) scale(0.44);
- }
- 33.33333% {
- transform: translateX(4vw) translateY(-10vh) scale(0.78);
- }
- 37.03704% {
- transform: translateX(-27vw) translateY(25vh) scale(0.31);
- }
- 40.74074% {
- transform: translateX(45vw) translateY(6vh) scale(0.39);
- }
- 44.44444% {
- transform: translateX(39vw) translateY(-27vh) scale(0.32);
- }
- 48.14815% {
- transform: translateX(-5vw) translateY(3vh) scale(0.59);
- }
- 51.85185% {
- transform: translateX(-27vw) translateY(18vh) scale(0.54);
- }
- 55.55556% {
- transform: translateX(-34vw) translateY(39vh) scale(0.82);
- }
- 59.25926% {
- transform: translateX(-34vw) translateY(18vh) scale(0.58);
- }
- 62.96296% {
- transform: translateX(32vw) translateY(5vh) scale(0.87);
- }
- 66.66667% {
- transform: translateX(13vw) translateY(-16vh) scale(0.62);
- }
- 70.37037% {
- transform: translateX(-38vw) translateY(31vh) scale(0.72);
- }
- 74.07407% {
- transform: translateX(9vw) translateY(11vh) scale(0.92);
- }
- 77.77778% {
- transform: translateX(-39vw) translateY(-31vh) scale(0.33);
- }
- 81.48148% {
- transform: translateX(-43vw) translateY(-3vh) scale(0.77);
- }
- 85.18519% {
- transform: translateX(-45vw) translateY(16vh) scale(0.76);
- }
- 88.88889% {
- transform: translateX(23vw) translateY(18vh) scale(0.93);
- }
- 92.59259% {
- transform: translateX(-34vw) translateY(-1vh) scale(0.29);
- }
- 96.2963% {
- transform: translateX(-36vw) translateY(-42vh) scale(0.76);
- }
- 100% {
- transform: translateX(-11vw) translateY(-32vh) scale(0.93);
- }
-}
-
-.firefly:nth-child(7) {
- animation-name: move7;
-}
-
-.firefly:nth-child(7)::before {
- animation-duration: 13s;
-}
-
-.firefly:nth-child(7)::after {
- animation-duration: 13s, 5685ms;
- animation-delay: 0ms, 3032ms;
-}
-
-@keyframes move7 {
- 0% {
- transform: translateX(5vw) translateY(46vh) scale(0.5);
- }
- 5% {
- transform: translateX(45vw) translateY(-21vh) scale(0.42);
- }
- 10% {
- transform: translateX(-15vw) translateY(-13vh) scale(0.71);
- }
- 15% {
- transform: translateX(49vw) translateY(-5vh) scale(0.29);
- }
- 20% {
- transform: translateX(29vw) translateY(22vh) scale(0.54);
- }
- 25% {
- transform: translateX(19vw) translateY(-23vh) scale(0.47);
- }
- 30% {
- transform: translateX(23vw) translateY(4vh) scale(0.65);
- }
- 35% {
- transform: translateX(-43vw) translateY(-22vh) scale(0.86);
- }
- 40% {
- transform: translateX(-10vw) translateY(15vh) scale(0.64);
- }
- 45% {
- transform: translateX(17vw) translateY(28vh) scale(0.52);
- }
- 50% {
- transform: translateX(-13vw) translateY(9vh) scale(0.91);
- }
- 55% {
- transform: translateX(31vw) translateY(-2vh) scale(0.95);
- }
- 60% {
- transform: translateX(-20vw) translateY(-22vh) scale(0.56);
- }
- 65% {
- transform: translateX(45vw) translateY(-35vh) scale(0.68);
- }
- 70% {
- transform: translateX(-11vw) translateY(-1vh) scale(0.48);
- }
- 75% {
- transform: translateX(-40vw) translateY(11vh) scale(0.88);
- }
- 80% {
- transform: translateX(4vw) translateY(-42vh) scale(0.75);
- }
- 85% {
- transform: translateX(50vw) translateY(6vh) scale(0.33);
- }
- 90% {
- transform: translateX(34vw) translateY(-21vh) scale(0.75);
- }
- 95% {
- transform: translateX(47vw) translateY(-16vh) scale(0.65);
- }
- 100% {
- transform: translateX(-22vw) translateY(-40vh) scale(0.65);
- }
-}
-
-.firefly:nth-child(8) {
- animation-name: move8;
-}
-
-.firefly:nth-child(8)::before {
- animation-duration: 9s;
-}
-
-.firefly:nth-child(8)::after {
- animation-duration: 9s, 6465ms;
- animation-delay: 0ms, 8013ms;
-}
-
-@keyframes move8 {
- 0% {
- transform: translateX(29vw) translateY(-25vh) scale(0.97);
- }
- 3.84615% {
- transform: translateX(27vw) translateY(49vh) scale(0.97);
- }
- 7.69231% {
- transform: translateX(29vw) translateY(-16vh) scale(0.45);
- }
- 11.53846% {
- transform: translateX(-47vw) translateY(-11vh) scale(0.53);
- }
- 15.38462% {
- transform: translateX(-28vw) translateY(-40vh) scale(0.76);
- }
- 19.23077% {
- transform: translateX(12vw) translateY(47vh) scale(0.71);
- }
- 23.07692% {
- transform: translateX(27vw) translateY(2vh) scale(0.31);
- }
- 26.92308% {
- transform: translateX(18vw) translateY(-24vh) scale(0.27);
- }
- 30.76923% {
- transform: translateX(40vw) translateY(-26vh) scale(0.33);
- }
- 34.61538% {
- transform: translateX(-12vw) translateY(-37vh) scale(0.45);
- }
- 38.46154% {
- transform: translateX(-49vw) translateY(-42vh) scale(0.87);
- }
- 42.30769% {
- transform: translateX(-1vw) translateY(28vh) scale(0.46);
- }
- 46.15385% {
- transform: translateX(-34vw) translateY(-21vh) scale(0.73);
- }
- 50% {
- transform: translateX(-2vw) translateY(-25vh) scale(0.55);
- }
- 53.84615% {
- transform: translateX(46vw) translateY(45vh) scale(0.46);
- }
- 57.69231% {
- transform: translateX(-10vw) translateY(-39vh) scale(0.26);
- }
- 61.53846% {
- transform: translateX(-34vw) translateY(11vh) scale(0.37);
- }
- 65.38462% {
- transform: translateX(0vw) translateY(-4vh) scale(0.87);
- }
- 69.23077% {
- transform: translateX(18vw) translateY(-2vh) scale(0.7);
- }
- 73.07692% {
- transform: translateX(-14vw) translateY(-1vh) scale(0.43);
- }
- 76.92308% {
- transform: translateX(-8vw) translateY(9vh) scale(0.77);
- }
- 80.76923% {
- transform: translateX(4vw) translateY(-14vh) scale(0.93);
- }
- 84.61538% {
- transform: translateX(-1vw) translateY(1vh) scale(0.72);
- }
- 88.46154% {
- transform: translateX(33vw) translateY(44vh) scale(0.95);
- }
- 92.30769% {
- transform: translateX(16vw) translateY(-7vh) scale(0.71);
- }
- 96.15385% {
- transform: translateX(23vw) translateY(-33vh) scale(0.6);
- }
- 100% {
- transform: translateX(47vw) translateY(-48vh) scale(0.86);
- }
-}
-
-.firefly:nth-child(9) {
- animation-name: move9;
-}
-
-.firefly:nth-child(9)::before {
- animation-duration: 13s;
-}
-
-.firefly:nth-child(9)::after {
- animation-duration: 13s, 5297ms;
- animation-delay: 0ms, 4389ms;
-}
-
-@keyframes move9 {
- 0% {
- transform: translateX(-41vw) translateY(-27vh) scale(0.46);
- }
- 5.88235% {
- transform: translateX(33vw) translateY(-27vh) scale(0.81);
- }
- 11.76471% {
- transform: translateX(34vw) translateY(30vh) scale(0.49);
- }
- 17.64706% {
- transform: translateX(-47vw) translateY(14vh) scale(0.62);
- }
- 23.52941% {
- transform: translateX(48vw) translateY(43vh) scale(0.37);
- }
- 29.41176% {
- transform: translateX(1vw) translateY(-31vh) scale(0.72);
- }
- 35.29412% {
- transform: translateX(-22vw) translateY(-31vh) scale(0.37);
- }
- 41.17647% {
- transform: translateX(-48vw) translateY(31vh) scale(0.39);
- }
- 47.05882% {
- transform: translateX(-46vw) translateY(-37vh) scale(0.45);
- }
- 52.94118% {
- transform: translateX(-43vw) translateY(-12vh) scale(0.26);
- }
- 58.82353% {
- transform: translateX(-9vw) translateY(28vh) scale(0.27);
- }
- 64.70588% {
- transform: translateX(-24vw) translateY(-26vh) scale(0.49);
- }
- 70.58824% {
- transform: translateX(-15vw) translateY(4vh) scale(0.96);
- }
- 76.47059% {
- transform: translateX(-35vw) translateY(-8vh) scale(0.64);
- }
- 82.35294% {
- transform: translateX(-23vw) translateY(-17vh) scale(0.95);
- }
- 88.23529% {
- transform: translateX(-27vw) translateY(-39vh) scale(0.64);
- }
- 94.11765% {
- transform: translateX(-42vw) translateY(35vh) scale(0.34);
- }
- 100% {
- transform: translateX(-3vw) translateY(14vh) scale(0.76);
- }
-}
-
-.firefly:nth-child(10) {
- animation-name: move10;
-}
-
-.firefly:nth-child(10)::before {
- animation-duration: 9s;
-}
-
-.firefly:nth-child(10)::after {
- animation-duration: 9s, 8266ms;
- animation-delay: 0ms, 3745ms;
-}
-
-@keyframes move10 {
- 0% {
- transform: translateX(0vw) translateY(-26vh) scale(0.3);
- }
- 3.84615% {
- transform: translateX(-32vw) translateY(33vh) scale(0.42);
- }
- 7.69231% {
- transform: translateX(-17vw) translateY(42vh) scale(0.88);
- }
- 11.53846% {
- transform: translateX(25vw) translateY(-13vh) scale(0.63);
- }
- 15.38462% {
- transform: translateX(43vw) translateY(-19vh) scale(0.31);
- }
- 19.23077% {
- transform: translateX(-28vw) translateY(-32vh) scale(0.56);
- }
- 23.07692% {
- transform: translateX(-38vw) translateY(-12vh) scale(0.87);
- }
- 26.92308% {
- transform: translateX(-39vw) translateY(-39vh) scale(0.5);
- }
- 30.76923% {
- transform: translateX(37vw) translateY(-39vh) scale(0.97);
- }
- 34.61538% {
- transform: translateX(-35vw) translateY(-18vh) scale(0.89);
- }
- 38.46154% {
- transform: translateX(50vw) translateY(-9vh) scale(0.98);
- }
- 42.30769% {
- transform: translateX(22vw) translateY(25vh) scale(0.74);
- }
- 46.15385% {
- transform: translateX(-49vw) translateY(0vh) scale(0.58);
- }
- 50% {
- transform: translateX(-18vw) translateY(22vh) scale(0.51);
- }
- 53.84615% {
- transform: translateX(42vw) translateY(0vh) scale(0.83);
- }
- 57.69231% {
- transform: translateX(-14vw) translateY(33vh) scale(0.89);
- }
- 61.53846% {
- transform: translateX(17vw) translateY(10vh) scale(0.79);
- }
- 65.38462% {
- transform: translateX(24vw) translateY(-26vh) scale(0.63);
- }
- 69.23077% {
- transform: translateX(-38vw) translateY(25vh) scale(0.38);
- }
- 73.07692% {
- transform: translateX(-43vw) translateY(3vh) scale(0.43);
- }
- 76.92308% {
- transform: translateX(14vw) translateY(-14vh) scale(0.89);
- }
- 80.76923% {
- transform: translateX(-32vw) translateY(-3vh) scale(0.38);
- }
- 84.61538% {
- transform: translateX(-29vw) translateY(4vh) scale(0.94);
- }
- 88.46154% {
- transform: translateX(17vw) translateY(-42vh) scale(0.31);
- }
- 92.30769% {
- transform: translateX(44vw) translateY(-18vh) scale(0.7);
- }
- 96.15385% {
- transform: translateX(10vw) translateY(-46vh) scale(0.52);
- }
- 100% {
- transform: translateX(-16vw) translateY(-21vh) scale(0.29);
- }
-}
-
-.firefly:nth-child(11) {
- animation-name: move11;
-}
-
-.firefly:nth-child(11)::before {
- animation-duration: 11s;
-}
-
-.firefly:nth-child(11)::after {
- animation-duration: 11s, 8283ms;
- animation-delay: 0ms, 7669ms;
-}
-
-@keyframes move11 {
- 0% {
- transform: translateX(-21vw) translateY(37vh) scale(0.55);
- }
- 3.7037% {
- transform: translateX(-30vw) translateY(15vh) scale(0.47);
- }
- 7.40741% {
- transform: translateX(-47vw) translateY(-32vh) scale(0.9);
- }
- 11.11111% {
- transform: translateX(11vw) translateY(-42vh) scale(0.94);
- }
- 14.81481% {
- transform: translateX(-21vw) translateY(-14vh) scale(0.48);
- }
- 18.51852% {
- transform: translateX(47vw) translateY(14vh) scale(0.32);
- }
- 22.22222% {
- transform: translateX(29vw) translateY(23vh) scale(0.36);
- }
- 25.92593% {
- transform: translateX(-36vw) translateY(-12vh) scale(0.26);
- }
- 29.62963% {
- transform: translateX(-24vw) translateY(-1vh) scale(0.94);
- }
- 33.33333% {
- transform: translateX(41vw) translateY(-42vh) scale(0.65);
- }
- 37.03704% {
- transform: translateX(29vw) translateY(-49vh) scale(0.35);
- }
- 40.74074% {
- transform: translateX(36vw) translateY(4vh) scale(0.97);
- }
- 44.44444% {
- transform: translateX(-45vw) translateY(29vh) scale(0.52);
- }
- 48.14815% {
- transform: translateX(14vw) translateY(28vh) scale(0.37);
- }
- 51.85185% {
- transform: translateX(-37vw) translateY(19vh) scale(0.38);
- }
- 55.55556% {
- transform: translateX(42vw) translateY(8vh) scale(0.84);
- }
- 59.25926% {
- transform: translateX(0vw) translateY(-11vh) scale(0.94);
- }
- 62.96296% {
- transform: translateX(0vw) translateY(-6vh) scale(0.31);
- }
- 66.66667% {
- transform: translateX(33vw) translateY(-36vh) scale(0.28);
- }
- 70.37037% {
- transform: translateX(-32vw) translateY(35vh) scale(0.96);
- }
- 74.07407% {
- transform: translateX(35vw) translateY(13vh) scale(0.71);
- }
- 77.77778% {
- transform: translateX(11vw) translateY(-19vh) scale(0.37);
- }
- 81.48148% {
- transform: translateX(-45vw) translateY(48vh) scale(0.88);
- }
- 85.18519% {
- transform: translateX(-48vw) translateY(-23vh) scale(0.39);
- }
- 88.88889% {
- transform: translateX(-44vw) translateY(14vh) scale(0.73);
- }
- 92.59259% {
- transform: translateX(37vw) translateY(-3vh) scale(0.52);
- }
- 96.2963% {
- transform: translateX(-20vw) translateY(-48vh) scale(0.29);
- }
- 100% {
- transform: translateX(13vw) translateY(-19vh) scale(0.89);
- }
-}
-
-.firefly:nth-child(12) {
- animation-name: move12;
-}
-
-.firefly:nth-child(12)::before {
- animation-duration: 15s;
-}
-
-.firefly:nth-child(12)::after {
- animation-duration: 15s, 8952ms;
- animation-delay: 0ms, 2128ms;
-}
-
-@keyframes move12 {
- 0% {
- transform: translateX(5vw) translateY(-33vh) scale(0.52);
- }
- 3.7037% {
- transform: translateX(32vw) translateY(41vh) scale(0.54);
- }
- 7.40741% {
- transform: translateX(29vw) translateY(4vh) scale(0.9);
- }
- 11.11111% {
- transform: translateX(-11vw) translateY(-24vh) scale(0.31);
- }
- 14.81481% {
- transform: translateX(-6vw) translateY(-41vh) scale(0.78);
- }
- 18.51852% {
- transform: translateX(4vw) translateY(-46vh) scale(0.34);
- }
- 22.22222% {
- transform: translateX(-34vw) translateY(-20vh) scale(0.57);
- }
- 25.92593% {
- transform: translateX(23vw) translateY(-20vh) scale(0.37);
- }
- 29.62963% {
- transform: translateX(50vw) translateY(34vh) scale(0.88);
- }
- 33.33333% {
- transform: translateX(32vw) translateY(-30vh) scale(0.88);
- }
- 37.03704% {
- transform: translateX(-13vw) translateY(47vh) scale(0.38);
- }
- 40.74074% {
- transform: translateX(21vw) translateY(-22vh) scale(0.96);
- }
- 44.44444% {
- transform: translateX(-45vw) translateY(-40vh) scale(0.88);
- }
- 48.14815% {
- transform: translateX(16vw) translateY(41vh) scale(0.79);
- }
- 51.85185% {
- transform: translateX(-34vw) translateY(37vh) scale(0.93);
- }
- 55.55556% {
- transform: translateX(31vw) translateY(-44vh) scale(0.66);
- }
- 59.25926% {
- transform: translateX(22vw) translateY(27vh) scale(0.66);
- }
- 62.96296% {
- transform: translateX(-35vw) translateY(5vh) scale(0.52);
- }
- 66.66667% {
- transform: translateX(26vw) translateY(29vh) scale(0.63);
- }
- 70.37037% {
- transform: translateX(-9vw) translateY(-15vh) scale(0.31);
- }
- 74.07407% {
- transform: translateX(5vw) translateY(12vh) scale(0.77);
- }
- 77.77778% {
- transform: translateX(13vw) translateY(-13vh) scale(0.66);
- }
- 81.48148% {
- transform: translateX(-19vw) translateY(-35vh) scale(0.5);
- }
- 85.18519% {
- transform: translateX(8vw) translateY(34vh) scale(0.56);
- }
- 88.88889% {
- transform: translateX(34vw) translateY(30vh) scale(0.29);
- }
- 92.59259% {
- transform: translateX(-46vw) translateY(49vh) scale(0.57);
- }
- 96.2963% {
- transform: translateX(-13vw) translateY(43vh) scale(0.66);
- }
- 100% {
- transform: translateX(-18vw) translateY(39vh) scale(0.88);
- }
-}
-
-.firefly:nth-child(13) {
- animation-name: move13;
-}
-
-.firefly:nth-child(13)::before {
- animation-duration: 15s;
-}
-
-.firefly:nth-child(13)::after {
- animation-duration: 15s, 8736ms;
- animation-delay: 0ms, 2163ms;
-}
-
-@keyframes move13 {
- 0% {
- transform: translateX(-30vw) translateY(36vh) scale(0.57);
- }
- 4.7619% {
- transform: translateX(-31vw) translateY(-32vh) scale(0.3);
- }
- 9.52381% {
- transform: translateX(-23vw) translateY(1vh) scale(0.83);
- }
- 14.28571% {
- transform: translateX(29vw) translateY(12vh) scale(1);
- }
- 19.04762% {
- transform: translateX(-13vw) translateY(32vh) scale(0.82);
- }
- 23.80952% {
- transform: translateX(-30vw) translateY(43vh) scale(0.83);
- }
- 28.57143% {
- transform: translateX(-20vw) translateY(10vh) scale(0.56);
- }
- 33.33333% {
- transform: translateX(46vw) translateY(48vh) scale(0.36);
- }
- 38.09524% {
- transform: translateX(-30vw) translateY(-6vh) scale(0.5);
- }
- 42.85714% {
- transform: translateX(15vw) translateY(-24vh) scale(0.52);
- }
- 47.61905% {
- transform: translateX(-47vw) translateY(9vh) scale(0.51);
- }
- 52.38095% {
- transform: translateX(31vw) translateY(38vh) scale(0.32);
- }
- 57.14286% {
- transform: translateX(34vw) translateY(33vh) scale(0.6);
- }
- 61.90476% {
- transform: translateX(20vw) translateY(25vh) scale(0.62);
- }
- 66.66667% {
- transform: translateX(-34vw) translateY(-30vh) scale(0.5);
- }
- 71.42857% {
- transform: translateX(-18vw) translateY(-9vh) scale(0.48);
- }
- 76.19048% {
- transform: translateX(4vw) translateY(25vh) scale(0.27);
- }
- 80.95238% {
- transform: translateX(24vw) translateY(7vh) scale(0.34);
- }
- 85.71429% {
- transform: translateX(-4vw) translateY(-23vh) scale(0.47);
- }
- 90.47619% {
- transform: translateX(5vw) translateY(41vh) scale(0.34);
- }
- 95.2381% {
- transform: translateX(28vw) translateY(-34vh) scale(0.95);
- }
- 100% {
- transform: translateX(2vw) translateY(9vh) scale(0.64);
- }
-}
-
-.firefly:nth-child(14) {
- animation-name: move14;
-}
-
-.firefly:nth-child(14)::before {
- animation-duration: 15s;
-}
-
-.firefly:nth-child(14)::after {
- animation-duration: 15s, 10545ms;
- animation-delay: 0ms, 1028ms;
-}
-
-@keyframes move14 {
- 0% {
- transform: translateX(-14vw) translateY(30vh) scale(0.36);
- }
- 4.7619% {
- transform: translateX(-10vw) translateY(4vh) scale(0.76);
- }
- 9.52381% {
- transform: translateX(-39vw) translateY(42vh) scale(0.86);
- }
- 14.28571% {
- transform: translateX(45vw) translateY(6vh) scale(0.76);
- }
- 19.04762% {
- transform: translateX(-34vw) translateY(28vh) scale(0.55);
- }
- 23.80952% {
- transform: translateX(14vw) translateY(21vh) scale(0.46);
- }
- 28.57143% {
- transform: translateX(22vw) translateY(-4vh) scale(0.93);
- }
- 33.33333% {
- transform: translateX(44vw) translateY(-27vh) scale(0.27);
- }
- 38.09524% {
- transform: translateX(-7vw) translateY(-6vh) scale(0.97);
- }
- 42.85714% {
- transform: translateX(-46vw) translateY(-8vh) scale(0.59);
- }
- 47.61905% {
- transform: translateX(-27vw) translateY(-44vh) scale(0.56);
- }
- 52.38095% {
- transform: translateX(-2vw) translateY(1vh) scale(0.61);
- }
- 57.14286% {
- transform: translateX(-23vw) translateY(13vh) scale(0.76);
- }
- 61.90476% {
- transform: translateX(-1vw) translateY(-30vh) scale(0.94);
- }
- 66.66667% {
- transform: translateX(5vw) translateY(29vh) scale(0.65);
- }
- 71.42857% {
- transform: translateX(47vw) translateY(-16vh) scale(0.44);
- }
- 76.19048% {
- transform: translateX(23vw) translateY(42vh) scale(0.36);
- }
- 80.95238% {
- transform: translateX(20vw) translateY(-35vh) scale(0.83);
- }
- 85.71429% {
- transform: translateX(23vw) translateY(-1vh) scale(0.3);
- }
- 90.47619% {
- transform: translateX(-39vw) translateY(17vh) scale(0.69);
- }
- 95.2381% {
- transform: translateX(-30vw) translateY(-26vh) scale(0.9);
- }
- 100% {
- transform: translateX(11vw) translateY(-41vh) scale(0.49);
- }
-}
-
-.firefly:nth-child(15) {
- animation-name: move15;
-}
-
-.firefly:nth-child(15)::before {
- animation-duration: 10s;
-}
-
-.firefly:nth-child(15)::after {
- animation-duration: 10s, 5182ms;
- animation-delay: 0ms, 7098ms;
-}
-
-@keyframes move15 {
- 0% {
- transform: translateX(12vw) translateY(-17vh) scale(0.67);
- }
- 5% {
- transform: translateX(48vw) translateY(23vh) scale(0.72);
- }
- 10% {
- transform: translateX(-30vw) translateY(-19vh) scale(0.34);
- }
- 15% {
- transform: translateX(40vw) translateY(-1vh) scale(0.95);
- }
- 20% {
- transform: translateX(15vw) translateY(45vh) scale(0.6);
- }
- 25% {
- transform: translateX(19vw) translateY(-22vh) scale(0.28);
- }
- 30% {
- transform: translateX(-7vw) translateY(35vh) scale(0.83);
- }
- 35% {
- transform: translateX(-29vw) translateY(-11vh) scale(0.68);
- }
- 40% {
- transform: translateX(-3vw) translateY(17vh) scale(0.93);
- }
- 45% {
- transform: translateX(-25vw) translateY(-2vh) scale(0.57);
- }
- 50% {
- transform: translateX(50vw) translateY(-9vh) scale(0.57);
- }
- 55% {
- transform: translateX(25vw) translateY(13vh) scale(0.72);
- }
- 60% {
- transform: translateX(22vw) translateY(16vh) scale(0.54);
- }
- 65% {
- transform: translateX(35vw) translateY(49vh) scale(0.64);
- }
- 70% {
- transform: translateX(-4vw) translateY(38vh) scale(0.79);
- }
- 75% {
- transform: translateX(44vw) translateY(43vh) scale(0.41);
- }
- 80% {
- transform: translateX(22vw) translateY(-7vh) scale(0.81);
- }
- 85% {
- transform: translateX(16vw) translateY(-8vh) scale(0.8);
- }
- 90% {
- transform: translateX(-13vw) translateY(48vh) scale(0.58);
- }
- 95% {
- transform: translateX(-27vw) translateY(-1vh) scale(0.31);
- }
- 100% {
- transform: translateX(-24vw) translateY(37vh) scale(0.99);
- }
-}
-
-@keyframes drift {
- 0% {
- transform: rotate(0deg);
- }
- 100% {
- transform: rotate(360deg);
- }
-}
-
-@keyframes flash {
- 0%,
- 30%,
- 100% {
- opacity: 0;
- box-shadow: 0 0 0vw 0vw yellow;
- }
- 5% {
- opacity: 1;
- box-shadow: 0 0 2vw 0.4vw yellow;
- }
-}
diff --git a/documentation/src/components/header/header.module.css b/documentation/src/components/header/header.module.css
deleted file mode 100644
index 1876d8ecb..000000000
--- a/documentation/src/components/header/header.module.css
+++ /dev/null
@@ -1,454 +0,0 @@
-@import url("https://fonts.googleapis.com/css2?family=Source+Sans+Pro:wght@200;300;400;600;700;900&display=swap");
-
-.container {
- position: relative;
- min-height: 400px;
- padding: 120px 0 160px;
- max-width: 100vw;
- overflow: hidden;
-}
-
-.wrapper {
- position: relative;
- z-index: 2;
-}
-
-.productHunt {
- position: absolute;
- bottom: 20px;
- left: 50%;
- transform: translate(-50%);
-}
-
-.productHunt img {
- width: 180px;
-}
-
-.logo {
- display: flex;
- width: auto;
- justify-content: center;
- margin-bottom: 50px;
-}
-
-.logo img {
- width: 200px;
-}
-
-html[data-theme="light"] body .logo img {
- content: url("/img/brand/HF_Black.svg") !important;
-}
-
-.title {
- margin: 0px auto 60px;
- text-align: center;
- font-size: 1.8rem;
- font-family: "Source Sans Pro", sans-serif;
- text-shadow: 0px 0px 3px var(--ifm-color-emphasis-100);
-}
-
-.tagline {
- font-size: 3.2em;
- max-width: 700px;
- margin: 0 auto;
- text-align: center;
- font-weight: 700;
- line-height: 1.1;
- font-family: "Source Sans Pro", sans-serif;
-}
-
-.tagline b {
- font-weight: 900;
-}
-
-.gradientLetters {
- background-color: var(--ifm-color-warning-dark);
- background-image: linear-gradient(
- to right,
- var(--ifm-color-warning),
- #d88e27,
- var(--ifm-color-primary-dark),
- var(--ifm-color-primary),
- #d88e27
- );
- background-size: 100%;
- -webkit-background-clip: text;
- -moz-background-clip: text;
- -webkit-text-fill-color: transparent;
- -moz-text-fill-color: transparent;
-}
-
-.addition {
- font-size: 1rem;
- font-weight: 500;
- margin-top: 20px;
- margin-bottom: 60px;
- text-align: center;
- color: var(--ifm-color-emphasis-600);
-}
-
-html[data-theme="dark"] .addition {
- color: var(--ifm-color-emphasis-300);
-}
-
-.addition span {
- color: var(--ifm-font-color-base) !important;
-}
-
-.buttons {
- display: flex;
- gap: 20px;
- justify-content: center;
- margin-bottom: 20;
-}
-.buttons a {
- position: relative;
- display: flex;
- align-items: center;
- justify-content: center;
- font-size: 16px;
- height: 42px;
- overflow: hidden;
- margin: 1px;
-}
-
-.buttons > * {
- box-shadow: 0 16px 18px -8px var(--shadow-color), 0 6px 8px -4px var(--shadow-color);
-}
-
-.buttons a:first-child {
- color: #2c2c2c;
- border: 0;
- background: radial-gradient(
- 100% 100% at 100% 0,
- var(--ifm-color-primary-lighter) 0,
- var(--ifm-color-warning-dark) 100%
- );
-}
-.buttons a:last-child {
- border: 0;
-}
-.buttons .wrapper {
- border-radius: var(--ifm-button-border-radius);
- overflow: hidden;
-}
-
-.glow {
- position: absolute;
- display: block;
- top: -50%;
- left: -50%;
- z-index: -9;
- display: block;
- height: 200%;
- width: 200%;
- overflow: hidden;
- background: linear-gradient(
- to right,
- rgba(255, 255, 255, 0) 20%,
- rgba(255, 255, 255, 0) 40%,
- #ecd08c 50%,
- #ecd08c 55%,
- rgba(255, 255, 255, 0) 70%,
- rgba(255, 255, 255, 0) 100%
- );
- background-size: 200% auto;
- border-radius: inherit;
- animation: shine 3s linear infinite;
-}
-
-@keyframes shine {
- to {
- background-position: 200% center;
- }
-}
-
-.powered {
- font-size: 0.8rem;
- font-weight: 400;
- font-family: "Source Sans Pro", sans-serif;
-}
-.powered a {
- margin-left: 2px;
-}
-
-@media (max-width: 650px) {
- .container {
- padding-top: 40px;
- }
- .title {
- margin: 0;
- }
- .projectName {
- display: none;
- }
- .tagline {
- font-size: 2.6em;
- }
-}
-
-@media (max-width: 450px) {
- .tagline {
- font-size: 2.2em;
- }
- .buttons {
- display: flex;
- flex-direction: column;
- justify-content: center;
- align-items: center;
- }
- .buttons > * {
- width: 210px;
- max-width: 100%;
- }
-}
-
-@media (max-width: 350px) {
- .tagline {
- font-size: 1.8em;
- }
-}
-
-/* Animation */
-
-.animation {
- position: absolute;
- z-index: -1;
- bottom: 0;
- left: 0;
- right: 0;
- overflow: hidden;
- transform: translateY(65%);
-}
-
-.waves {
- width: 100%;
- height: 330px;
- min-width: 1300px;
-}
-
-.waves > path,
-.waves g path {
- -webkit-animation: a 17390ms ease-in-out infinite alternate-reverse both;
- -moz-animation: a 17390ms ease-in-out infinite alternate-reverse both;
- -ms-animation: a 17390ms ease-in-out infinite alternate-reverse both;
- -o-animation: a 17390ms ease-in-out infinite alternate-reverse both;
- animation: a 17390ms ease-in-out infinite alternate-reverse both;
- -webkit-animation-timing-function: cubic-bezier(0.25, 0, 0.75, 1);
- -moz-animation-timing-function: cubic-bezier(0.25, 0, 0.75, 1);
- -ms-animation-timing-function: cubic-bezier(0.25, 0, 0.75, 1);
- -o-animation-timing-function: cubic-bezier(0.25, 0, 0.75, 1);
- animation-timing-function: cubic-bezier(0.25, 0, 0.75, 1);
- -webkit-will-change: transform;
- -moz-will-change: transform;
- -ms-will-change: transform;
- -o-will-change: transform;
- will-change: transform;
-}
-
-.waves > path:nth-of-type(1),
-.waves > g path:nth-of-type(1) {
- -webkit-animation-duration: 20580ms;
- -moz-animation-duration: 20580ms;
- -ms-animation-duration: 20580ms;
- -o-animation-duration: 20580ms;
- animation-duration: 20580ms;
-}
-
-.waves > path:nth-of-type(2),
-.waves > g path:nth-of-type(2) {
- -webkit-animation-delay: -2690ms;
- -moz-animation-delay: -2690ms;
- -ms-animation-delay: -2690ms;
- -o-animation-delay: -2690ms;
- animation-delay: -2690ms;
- -webkit-animation-duration: 13580ms;
- -moz-animation-duration: 13580ms;
- -ms-animation-duration: 13580ms;
- -o-animation-duration: 13580ms;
- animation-duration: 13580ms;
-}
-
-.container g > path:nth-of-type(1) {
- -webkit-animation-delay: -820ms;
- -moz-animation-delay: -820ms;
- -ms-animation-delay: -820ms;
- -o-animation-delay: -820ms;
- animation-delay: -820ms;
- -webkit-animation-duration: 10730ms;
- -moz-animation-duration: 10730ms;
- -ms-animation-duration: 10730ms;
- -o-animation-duration: 10730ms;
- animation-duration: 10730ms;
-}
-
-.waves > path:nth-of-type(1),
-.container g > path:nth-of-type(2) {
- -webkit-animation-direction: alternate;
- -moz-animation-direction: alternate;
- -ms-animation-direction: alternate;
- -o-animation-direction: alternate;
- animation-direction: alternate;
-}
-
-@-webkit-keyframes a {
- 0% {
- -webkit-transform: translate(-750px);
- transform: translate(-750px);
- }
-
- 100% {
- -webkit-transform: translate(-20px);
- transform: translate(-20px);
- }
-}
-
-@-moz-keyframes a {
- 0% {
- -moz-transform: translate(-750px);
- transform: translate(-750px);
- }
-
- 100% {
- -moz-transform: translate(-20px);
- transform: translate(-20px);
- }
-}
-
-@-ms-keyframes a {
- 0% {
- -ms-transform: translate(-750px);
- transform: translate(-750px);
- }
-
- 100% {
- -ms-transform: translate(-20px);
- transform: translate(-20px);
- }
-}
-
-@-o-keyframes a {
- 0% {
- -o-transform: translate(-750px);
- transform: translate(-750px);
- }
-
- 100% {
- -o-transform: translate(-20px);
- transform: translate(-20px);
- }
-}
-
-@keyframes a {
- 0% {
- -webkit-transform: translate(-750px);
- -moz-transform: translate(-750px);
- -ms-transform: translate(-750px);
- -o-transform: translate(-750px);
- transform: translate(-750px);
- }
-
- 100% {
- -webkit-transform: translate(-20px);
- -moz-transform: translate(-20px);
- -ms-transform: translate(-20px);
- -o-transform: translate(-20px);
- transform: translate(-20px);
- }
-}
-
-/* Stars */
-.stars {
- display: flex;
- margin-top: -35px;
- margin-bottom: 40px;
-}
-
-.githubStars {
- display: flex;
- align-items: center;
- justify-content: center;
- color: var(--ifm-font-color-base) !important;
- font-size: 12px;
- font-weight: 600;
- text-decoration: none !important;
- margin: 0 auto;
- font-family: var(--ifm-font-family-base);
- border-radius: 8px;
- background: -webkit-gradient(
- linear,
- left top,
- left bottom,
- color-stop(4%, var(--ifm-color-emphasis-200)),
- color-stop(100%, var(--section-background))
- );
- width: auto;
- height: 26px;
- padding: 6px 10px;
- gap: 5px;
-}
-
-html[data-theme="light"] .githubStars {
- background: -webkit-gradient(
- linear,
- left top,
- left bottom,
- color-stop(4%, var(--ifm-color-emphasis-100)),
- color-stop(100%, var(--ifm-color-emphasis-400))
- );
- box-shadow: var(--ifm-color-emphasis-600) 0px 6px 30px -8px;
-}
-
-.githubStars svg {
- position: relative;
- z-index: 2;
- height: 14px;
- min-width: 14px;
- margin-right: 1px;
-}
-
-.githubStarsCount {
- font-weight: 700;
-}
-
-.githubStars:hover {
- opacity: 0.7;
-}
-
-.glow {
- border-radius: 100%;
- background: radial-gradient(
- var(--ifm-color-emphasis-300),
- var(--ifm-color-emphasis-200),
- var(--ifm-color-emphasis-100),
- rgba(0, 0, 0, 0)
- );
- transform: translate(-50%, -50%);
-}
-
-.glowFirst {
- position: absolute;
- top: 0;
- left: 25%;
- opacity: 0.12;
- width: 500px;
- height: 500px;
-}
-
-.glowSecond {
- position: absolute;
- top: 10%;
- left: 80%;
- opacity: 0.09;
- width: 700px;
- height: 700px;
-}
-
-.glowThird {
- position: absolute;
- top: 120%;
- left: 48%;
- opacity: 0.2;
- width: 1000px;
- height: 700px;
-}
diff --git a/documentation/src/components/header/header.tsx b/documentation/src/components/header/header.tsx
deleted file mode 100644
index 62f505aaa..000000000
--- a/documentation/src/components/header/header.tsx
+++ /dev/null
@@ -1,66 +0,0 @@
-/* eslint-disable import/order */
-import React from "react";
-import clsx from "clsx";
-import Link from "@docusaurus/Link";
-
-import styles from "./header.module.css";
-import "./animation.scss";
-
-export function Header(): JSX.Element {
- return (
-
- );
-}
diff --git a/documentation/src/components/highlighter/highlighter.tsx b/documentation/src/components/highlighter/highlighter.tsx
new file mode 100644
index 000000000..ea2f29ddc
--- /dev/null
+++ b/documentation/src/components/highlighter/highlighter.tsx
@@ -0,0 +1,107 @@
+/* eslint-disable @typescript-eslint/no-use-before-define */
+import React, { useRef, useState, useEffect } from "react";
+import MousePosition from "@site/src/hooks/use-mouse-position";
+
+type HighlighterProps = {
+ children: React.ReactNode;
+ className?: string;
+ refresh?: boolean;
+};
+
+const findNode = (node: HTMLElement, className: string): HTMLElement | null => {
+ if (node.classList.contains(className)) {
+ return node;
+ }
+ if (node.children) {
+ const element = Array.from(node.children).find((item) => findNode(item as HTMLElement, className)) as HTMLElement;
+ return element || null;
+ }
+ return null;
+};
+
+export const Highlighter = ({ children, className = "", refresh = false }: HighlighterProps) => {
+ const containerRef = useRef(null);
+ const mousePosition = MousePosition();
+ const mouse = useRef<{ x: number; y: number }>({ x: 0, y: 0 });
+ const containerSize = useRef<{ w: number; h: number }>({ w: 0, h: 0 });
+ const [boxes, setBoxes] = useState>([]);
+
+ useEffect(() => {
+ if (containerRef.current) {
+ setBoxes(
+ Array.from(containerRef.current.children)
+ .map((el) => findNode(el as HTMLElement, "highlighter-item") as HTMLElement)
+ .filter(Boolean),
+ );
+ }
+ }, []);
+
+ useEffect(() => {
+ initContainer();
+ window.addEventListener("resize", initContainer);
+
+ return () => {
+ window.removeEventListener("resize", initContainer);
+ };
+ }, [setBoxes]);
+
+ useEffect(() => {
+ onMouseMove();
+ }, [mousePosition]);
+
+ useEffect(() => {
+ initContainer();
+ }, [refresh]);
+
+ const initContainer = () => {
+ if (containerRef.current) {
+ containerSize.current.w = containerRef.current.offsetWidth;
+ containerSize.current.h = containerRef.current.offsetHeight;
+ }
+ };
+
+ const onMouseMove = () => {
+ if (containerRef.current) {
+ const rect = containerRef.current.getBoundingClientRect();
+ const { w, h } = containerSize.current;
+ const x = mousePosition.x - rect.left;
+ const y = mousePosition.y - rect.top;
+ const inside = x < w && x > 0 && y < h && y > 0;
+ if (inside) {
+ mouse.current.x = x;
+ mouse.current.y = y;
+ boxes.forEach((box) => {
+ const boxX = -(box.getBoundingClientRect().left - rect.left) + mouse.current.x;
+ const boxY = -(box.getBoundingClientRect().top - rect.top) + mouse.current.y;
+ box.style.setProperty("--mouse-x", `${boxX}px`);
+ box.style.setProperty("--mouse-y", `${boxY}px`);
+ });
+ }
+ }
+ };
+
+ return (
+
+ {children}
+
+ );
+};
+
+type HighlighterItemProps = {
+ children: React.ReactNode;
+ className?: string;
+};
+
+export function HighlighterItem({ children, className = "" }: HighlighterItemProps) {
+ const colorsDark =
+ "dark:border-0 dark:bg-zinc-800/80 dark:before:bg-yellow-500 dark:after:[background:_radial-gradient(250px_circle_at_var(--mouse-x)_var(--mouse-y),theme(colors.zinc.400),transparent)]";
+ const colorsLight =
+ "bg-white/10 before:bg-yellow-300 after:[background:_radial-gradient(250px_circle_at_var(--mouse-x)_var(--mouse-y),theme(colors.zinc.200),transparent)]";
+ return (
+
+ {children}
+
+ );
+}
diff --git a/documentation/src/components/highlighter/index.ts b/documentation/src/components/highlighter/index.ts
new file mode 100644
index 000000000..10db2b42b
--- /dev/null
+++ b/documentation/src/components/highlighter/index.ts
@@ -0,0 +1 @@
+export * from "./highlighter";
diff --git a/documentation/src/components/index.ts b/documentation/src/components/index.ts
index 60ebb4111..47ff94aef 100644
--- a/documentation/src/components/index.ts
+++ b/documentation/src/components/index.ts
@@ -1,7 +1,16 @@
-export * from "./features/features";
-export * from "./description/description";
-export * from "./creators/creators";
-export * from "./promotion/promotion";
-export * from "./header/header";
-export * from "./partners/partners";
-export * from "./preview/preview";
+export * from "./description";
+export * from "./fade-in";
+export * from "./highlighter";
+export * from "./particles";
+export * from "./nav-tabs/nav-tabs";
+export * from "./npm-install/npm-install";
+export * from "./package-details/package-details";
+export * from "./presentation/presentation";
+export * from "./scale-in";
+export * from "./scale-out";
+export * from "./soon";
+export * from "./title";
+export * from "./ui/noise";
+export * from "./ui/docs-card";
+export * from "./show-more/show-more";
+export * from "./link-card/link-card";
diff --git a/documentation/src/components/landing/blocks/big-block/big-block.tsx b/documentation/src/components/landing/blocks/big-block/big-block.tsx
new file mode 100644
index 000000000..7fab56d9d
--- /dev/null
+++ b/documentation/src/components/landing/blocks/big-block/big-block.tsx
@@ -0,0 +1,64 @@
+import { Particles, FadeIn, HighlighterItem, Title, Description } from "@site/src/components";
+
+export const BigBlock = ({ title, description, img }: { title: string; description: string; img: React.ReactNode }) => {
+ return (
+
+
+
+
+
+ {/* Blurred shape */}
+
+ {/* Radial gradient */}
+
+ {/* Text */}
+
+
+
+
+ {title}
+
+ {description}
+
+
+
+
+
+ Learn more{" "}
+
+ →
+
+
+
+
+
+ {/* Image */}
+
{img}
+
+
+
+
+ );
+};
diff --git a/documentation/src/components/landing/blocks/blocks.tsx b/documentation/src/components/landing/blocks/blocks.tsx
new file mode 100644
index 000000000..d667f6107
--- /dev/null
+++ b/documentation/src/components/landing/blocks/blocks.tsx
@@ -0,0 +1,128 @@
+/* eslint-disable react/no-array-index-key */
+import Link from "@docusaurus/Link";
+import { Particles } from "@site/src/components/particles";
+import { Highlighter } from "@site/src/components/highlighter";
+import { FadeIn } from "@site/src/components/fade-in/fade-in";
+import { Stage } from "@react-theater/scroll";
+import { Description, Title } from "@site/src/components";
+import App from "@site/static/img/previews/app.png";
+
+import { BigBlock } from "./big-block/big-block";
+import { MediumBlock } from "./medium-block/medium-block";
+
+const FeatureImg02 = "/img/feature-integrations.png";
+const FeatureImg03 = "/img/feature-image-03.png";
+
+export const Blocks = () => {
+ return (
+
+ {/* Particles animation */}
+
+
+
+
+ {/* Section header */}
+
+
+
+
+
+
+
+ Simply
+
+
+
+
+
+ Faster.
+
+
+
+
+ Better.
+
+
+
+
+
+
+
+
+ Hyper Fetch provides a powerful, type-safe, backend & framework agnostic architecture for efficient
+ data exchange.
+
+
+
+
+ {/* Highlighted boxes */}
+
+ {/* Blurred shape */}
+
+
+
+
+ }
+ />
+
+
+
+ }
+ />
+
+
+
+ }
+ />
+
+
+
+
+
+
+ );
+};
diff --git a/documentation/src/components/landing/blocks/index.ts b/documentation/src/components/landing/blocks/index.ts
new file mode 100644
index 000000000..987a00f28
--- /dev/null
+++ b/documentation/src/components/landing/blocks/index.ts
@@ -0,0 +1 @@
+export * from "./blocks";
diff --git a/documentation/src/components/landing/blocks/medium-block/medium-block.tsx b/documentation/src/components/landing/blocks/medium-block/medium-block.tsx
new file mode 100644
index 000000000..b3000ef30
--- /dev/null
+++ b/documentation/src/components/landing/blocks/medium-block/medium-block.tsx
@@ -0,0 +1,48 @@
+import { Description, FadeIn, HighlighterItem, Title } from "@site/src/components";
+import { ArrowRight } from "lucide-react";
+
+export const MediumBlock = ({
+ img,
+ title,
+ description,
+}: {
+ img: React.ReactNode;
+ title: string;
+ description: string;
+}) => {
+ return (
+
+
+
+
+ {/* Radial gradient */}
+
+
+ {/* Text */}
+
+
+
+ {title}
+
+
+ {description}
+
+
+
+ Learn more
+
+
+ {/* Image */}
+
{img}
+
+
+
+
+
+ );
+};
diff --git a/documentation/src/components/landing/blocks/small-block/small-block.tsx b/documentation/src/components/landing/blocks/small-block/small-block.tsx
new file mode 100644
index 000000000..2fb16103d
--- /dev/null
+++ b/documentation/src/components/landing/blocks/small-block/small-block.tsx
@@ -0,0 +1,46 @@
+import { Description, FadeIn, HighlighterItem, Title } from "@site/src/components";
+import { getAnimationValue } from "@site/src/utils/animation";
+
+export const SmallBlock = ({
+ title,
+ description,
+ index = 1,
+}: {
+ title: string;
+ description: string;
+ index?: number;
+}) => {
+ return (
+
+
+
+
+ {/* Radial gradient */}
+
+ {/* Text */}
+
+
+
+ {title}
+
+
+ {description}
+
+
+
+
+
+
+
+ );
+};
diff --git a/documentation/src/components/landing/call-to-action/call-to-action.tsx b/documentation/src/components/landing/call-to-action/call-to-action.tsx
new file mode 100644
index 000000000..312bc7674
--- /dev/null
+++ b/documentation/src/components/landing/call-to-action/call-to-action.tsx
@@ -0,0 +1,69 @@
+/* eslint-disable jsx-a11y/anchor-is-valid */
+import Link from "@docusaurus/Link";
+import { Description, Title } from "@site/src/components";
+import { ArrowRight, Download } from "lucide-react";
+
+export const CallToAction = () => {
+ return (
+
+
+
+ {/* Radial gradient */}
+
+ {/* Blurred shape */}
+
+ {/* Content */}
+
+
+
+ Build with HyperFetch
+
+
Try it for yourself!
+
+
+ Get Started
+
+
+
Download HyperFlow
+
+
+
+
+
+
+ );
+};
diff --git a/documentation/src/components/landing/call-to-action/index.ts b/documentation/src/components/landing/call-to-action/index.ts
new file mode 100644
index 000000000..7daad59b4
--- /dev/null
+++ b/documentation/src/components/landing/call-to-action/index.ts
@@ -0,0 +1 @@
+export * from "./call-to-action";
diff --git a/documentation/src/components/landing/clients/clients.tsx b/documentation/src/components/landing/clients/clients.tsx
new file mode 100644
index 000000000..f9597c120
--- /dev/null
+++ b/documentation/src/components/landing/clients/clients.tsx
@@ -0,0 +1,80 @@
+import { useEffect } from "react";
+import Swiper, { Autoplay } from "swiper";
+import { Particles } from "@site/src/components/particles";
+import Client01 from "@site/static/img/client-01.svg";
+import Client02 from "@site/static/img/client-02.svg";
+import Client03 from "@site/static/img/client-03.svg";
+import Client04 from "@site/static/img/client-04.svg";
+import Client05 from "@site/static/img/client-05.svg";
+import Client06 from "@site/static/img/client-06.svg";
+import "swiper/swiper.min.css";
+
+// eslint-disable-next-line react-hooks/rules-of-hooks
+Swiper.use([Autoplay]);
+
+export const Clients = () => {
+ useEffect(() => {
+ const carousel = new Swiper(".clients-carousel", {
+ slidesPerView: "auto",
+ spaceBetween: 64,
+ centeredSlides: true,
+ loop: true,
+ speed: 5000,
+ noSwiping: true,
+ noSwipingClass: "swiper-slide",
+ autoplay: {
+ delay: 0,
+ disableOnInteraction: true,
+ },
+ });
+ return () => {
+ carousel.destroy?.();
+ };
+ }, []);
+
+ return (
+
+
+ Companies that use{" "}
+
+ BetterTyped
+ {" "}
+ open-source software.
+
+
+ {/* Particles animation */}
+
+
+
+ {/* Carousel built with Swiper.js [https://swiperjs.com/] */}
+ {/* * Custom styles in src/css/additional-styles/theme.scss */}
+
+
+ {/* Carousel items */}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/documentation/src/components/landing/clients/index.ts b/documentation/src/components/landing/clients/index.ts
new file mode 100644
index 000000000..b8fd0ad69
--- /dev/null
+++ b/documentation/src/components/landing/clients/index.ts
@@ -0,0 +1 @@
+export * from "./clients";
diff --git a/documentation/src/components/landing/example/example.tsx b/documentation/src/components/landing/example/example.tsx
new file mode 100644
index 000000000..f8f4e0c59
--- /dev/null
+++ b/documentation/src/components/landing/example/example.tsx
@@ -0,0 +1,77 @@
+import React from "react";
+import { Stage } from "@react-theater/scroll";
+import { FadeIn, Title } from "@site/src/components";
+
+export function Example(): JSX.Element {
+ return (
+
+
+
+
+
+
+
+
+
+ Simply
+
+
+
+
+
+ Faster.
+
+
+
+
+ Better.
+
+
+
+
+
+
+
+
+ Reduce the time needed to handle state and reducers. Streamline HTTP adapter setup and its dependencies.
+ Everything is set up right after installation in a fully configured environment with no external
+ dependencies!
+
+
+
+
+ {/* Blurred shape */}
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/documentation/src/components/features/animation.scss b/documentation/src/components/landing/features/animation.scss
similarity index 100%
rename from documentation/src/components/features/animation.scss
rename to documentation/src/components/landing/features/animation.scss
diff --git a/documentation/src/components/landing/features/features.tsx b/documentation/src/components/landing/features/features.tsx
new file mode 100644
index 000000000..5bb9f6c09
--- /dev/null
+++ b/documentation/src/components/landing/features/features.tsx
@@ -0,0 +1,271 @@
+/* eslint-disable react/no-array-index-key */
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+import React, { useEffect } from "react";
+import Link from "@docusaurus/Link";
+import { TimelineMax, Back } from "gsap";
+import { Theatre } from "@react-theater/scroll";
+import { Atom, Database, Fingerprint, LucideProps, Server, TrendingUpDown, Wifi } from "lucide-react";
+import { getAnimationValue } from "@site/src/utils/animation";
+import { FadeIn, Particles, Title } from "@site/src/components";
+
+import "./animation.scss";
+
+type FeatureItem = {
+ name: string;
+ description: string;
+ icon: React.ForwardRefExoticComponent & React.RefAttributes>;
+ link: JSX.Element;
+};
+
+// const FeatureList: FeatureItem[] = [
+// {
+// description: "Simple setup",
+// link: Read more,
+// },
+// {
+// description: "Automatic caching",
+// link: Read more,
+// },
+// {
+// description: "Built-in adapter",
+// link: Read more,
+// },
+// {
+// description: "Request cancellation",
+// link: Read more,
+// },
+// {
+// description: "Persistence",
+// link: Read more,
+// },
+// {
+// description: "Easy to test",
+// link: Read more,
+// },
+// {
+// description: "Window Focus/Blur Events",
+// link: Read more,
+// },
+// {
+// description: "SSR Support",
+// link: Read more,
+// },
+// {
+// description: "Authentication",
+// link: Read more,
+// },
+// {
+// description: "Queueing",
+// link: Read more,
+// },
+// {
+// description: "Offline first ready",
+// link: Read more,
+// },
+// {
+// description: "Prefetching",
+// link: Read more,
+// },
+// ];
+
+const features: FeatureItem[] = [
+ {
+ name: "Automatic caching",
+ description: "Automatically caches responses and reuses them when making the same request again.",
+ icon: Database,
+ link: (
+
+ Read more
+
+ ),
+ },
+ {
+ name: "Data Persistance",
+ description: "Persists your data to the local storage or indexedDB to reuse it when needed.",
+ icon: Atom,
+ link: (
+
+ Read more
+
+ ),
+ },
+ {
+ name: "SSR & Server Components support",
+ description: "Supports server-side rendering and server components out of the box.",
+ icon: Server,
+ link: (
+
+ Read more
+
+ ),
+ },
+ {
+ name: "Built-in Authentication",
+ description: "Built-in authentication allow you to easily manage user sessions.",
+ icon: Fingerprint,
+ link: (
+
+ Read more
+
+ ),
+ },
+ {
+ name: "Offline First",
+ description:
+ "Automatically uses cached data when the user is offline, and updates the cache when the user is online.",
+ icon: Wifi,
+ link: (
+
+ Read more
+
+ ),
+ },
+ {
+ name: "Prefetching",
+ description: "Prefetch data before components mount, so that it's available instantly when needed.",
+ icon: TrendingUpDown,
+ link: (
+
+ Read more
+
+ ),
+ },
+];
+
+export function Features(): JSX.Element {
+ useEffect(() => {
+ const bolt = document.querySelector(".bolt");
+ const element = bolt.querySelector("div");
+
+ const animation = new TimelineMax({
+ onStart() {
+ bolt.classList.add("animate");
+ },
+ onComplete() {
+ bolt.classList.remove("animate");
+ setTimeout(() => {
+ animation.restart();
+ }, 1000);
+ },
+ })
+ .set(element, {
+ rotation: 360,
+ })
+ .to(element, 0.7, {
+ y: 80,
+ rotation: 370,
+ })
+ .to(element, 0.6, {
+ y: -140,
+ rotation: 20,
+ })
+ .to(element, 0.1, {
+ rotation: -24,
+ y: 80,
+ })
+ .to(element, 0.8, {
+ ease: Back.easeOut.config(1.6),
+ rotation: 0,
+ y: 0,
+ });
+ }, []);
+
+ return (
+
+
+ {/* Illustration */}
+
+
+
+
+
+
+
+ {/* Bolt */}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* Section header */}
+
+
+
+
+ The future is now.
+
+
+
+
+
+ Control your architecture
+
+
+
+
+ Easily connect to the events that power our architecture and confidently create your own logic. We give
+ you full control over your data flow like no other framework can.
+
+
+
+
+ {/* Features list */}
+
+
+ {/* Feature */}
+ {features.map((feature, index) => (
+
+
+
+
{feature.name}
+
+ {feature.description}
+ {feature.link}
+
+ ))}
+
+
+
+
+
+ You can find more details in{" "}
+
+ Comparison
+
+
+
+
+
+
+ );
+}
diff --git a/documentation/src/components/landing/hero/beams.tsx b/documentation/src/components/landing/hero/beams.tsx
new file mode 100644
index 000000000..a238412c2
--- /dev/null
+++ b/documentation/src/components/landing/hero/beams.tsx
@@ -0,0 +1,137 @@
+/* eslint-disable react/no-array-index-key */
+import React from "react";
+import { motion } from "motion/react";
+import { cn } from "@site/src/lib/utils";
+
+export const BackgroundBeams = React.memo(({ className }: { className?: string }) => {
+ const paths = [
+ "M-137.178 380.636C-154.748 451.441 -94.4807 523.24 -24.1997 542.72C46.0946 562.231 121.053 542.636 189.627 517.656C258.214 492.706 326.535 461.938 399.408 458.549C550.233 451.563 678.856 560.701 786.951 665.993C895.046 771.285 1014.48 886.316 1165.16 896.055C1283.3 903.672 1394.25 843.843 1510.08 819.311C1712.27 776.47 1935 850.273 2071.41 1005.39",
+ "M-136.881 360.952C-154.491 431.664 -94.8608 503.517 -24.9372 523.7C-18.6934 525.52 -12.3837 526.982 -6.06092 528.219C58.3782 540.505 126.062 523.086 188.564 501.119C200.633 496.882 212.698 492.464 224.763 488.045C281.404 467.28 338.47 446.478 398.471 444.009C417.913 443.194 437.016 444.319 455.736 447.111C582.04 465.868 691.257 560.643 784.57 652.953C791.344 659.673 798.162 666.409 805.025 673.164C906.625 773.155 1018.39 874.014 1157.24 888.215C1196.96 892.271 1236.28 889.867 1275.9 881.843C1322.67 872.39 1368.88 855.488 1414.4 839.391C1445.49 828.406 1476.43 817.774 1507.92 809.766C1522.72 806.002 1537.68 802.865 1552.79 800.4C1648.94 784.658 1750.32 796.514 1842.48 831.343C1934.87 866.259 2018.21 923.78 2082.74 998.507",
+ "M-136.585 341.267C-154.253 411.93 -95.272 483.806 -25.7059 504.692C-19.4798 506.556 -13.2054 508.107 -6.90021 509.388C57.261 522.306 124.91 505.745 187.533 484.568C199.624 480.468 211.68 476.2 223.767 471.918C280.475 451.82 337.63 431.566 397.552 429.424C416.971 428.729 436.057 429.898 454.772 432.765C581.033 452.017 689.772 546.96 782.237 639.855C788.95 646.601 795.72 653.395 802.49 660.19C903.012 760.827 1012.87 861.186 1149.43 880.259C1189.32 885.848 1229.14 886.05 1269.94 878.727C1318.16 870.08 1365.73 851.749 1411.69 833.854C1443.06 821.648 1474.07 809.558 1505.78 800.176C1520.71 795.771 1535.76 792.006 1551.1 788.966C1648.65 769.581 1753.94 780.893 1848.66 817.224C1943.58 853.613 2028.34 914.185 2094.06 991.663",
+ "M-136.321 321.595C-154.028 392.165 -95.7151 464.109 -26.4888 485.654C-20.3113 487.576 -14.0721 489.215 -7.7846 490.54C56.1429 504.108 123.726 488.417 186.456 468C198.538 464.05 210.661 459.937 222.739 455.806C279.514 436.374 336.727 416.682 396.6 414.853C415.985 414.246 435.035 415.504 453.733 418.415C579.906 438.144 688.199 533.243 779.828 626.753C786.492 633.557 793.169 640.391 799.877 647.212C899.335 748.527 1007.36 848.464 1141.51 872.344C1181.64 879.483 1221.9 882.243 1263.91 875.607C1313.58 867.798 1362.51 848.007 1408.89 828.281C1440.57 814.843 1471.61 801.277 1503.54 790.551C1518.56 785.488 1533.79 781.1 1549.32 777.498C1648.27 754.471 1757.46 765.207 1854.72 803.041C1952.2 840.932 2038.37 904.525 2105.3 984.74",
+ "M-136.038 301.881C-153.772 372.39 -96.1084 444.357 -27.2704 466.618C-21.0973 468.614 -14.92 470.28 -8.66779 471.694C54.995 485.925 122.531 471.06 185.367 451.403C197.485 447.621 209.585 443.627 221.717 439.619C278.559 420.855 335.874 401.741 395.686 400.196C415.048 399.708 434.081 401.01 452.743 404.009C578.859 424.203 686.657 519.514 777.501 613.582C784.103 620.412 790.731 627.304 797.36 634.196C895.739 736.157 1002 835.903 1133.68 864.359C1174.02 873.093 1214.78 878.384 1257.95 872.418C1309.12 865.433 1359.37 844.195 1406.19 822.671C1438.14 807.981 1469.26 792.988 1501.44 780.875C1516.54 775.184 1531.95 770.173 1547.69 765.965C1648.04 739.264 1761.14 749.486 1860.95 788.793C1960.97 828.156 2048.56 894.799 2116.7 977.753",
+ "M-135.742 282.197C-153.546 352.626 -96.5063 424.678 -28.039 447.611C-21.9144 449.666 -15.7415 451.406 -9.50693 452.864C53.8912 467.759 121.379 453.72 184.335 434.854C196.476 431.209 208.598 427.351 220.721 423.494C277.63 405.397 335.034 386.831 394.766 385.612C414.093 385.213 433.091 386.603 451.78 389.664C577.852 410.353 685.159 505.802 775.168 600.485C781.721 607.373 788.244 614.274 794.824 621.223C892.125 723.831 996.651 823.552 1125.85 856.449C1166.46 866.781 1207.61 874.582 1251.98 869.347C1304.59 863.168 1356.2 840.502 1403.49 817.165C1435.75 801.242 1466.94 784.791 1499.3 771.316C1514.54 764.985 1530.04 759.346 1546.02 754.564C1647.76 724.22 1764.76 733.867 1867.12 774.676C1969.66 815.555 2058.69 885.205 2128.04 970.896",
+ "M-135.446 262.512C-153.277 332.879 -96.9175 404.967 -28.7767 428.59C-22.7007 430.702 -16.5322 432.518 -10.3462 434.033C52.805 449.547 120.24 436.409 183.259 418.286C195.422 414.777 207.549 411.101 219.694 407.381C276.657 389.92 334.132 371.946 393.816 371.041C413.121 370.761 432.114 372.227 450.755 375.345C576.77 396.498 683.613 492.146 772.774 587.414C779.265 594.328 785.739 601.287 792.226 608.276C888.449 711.531 991.309 811.383 1117.94 848.533C1158.82 860.509 1200.38 870.805 1245.95 866.227C1300.02 860.886 1352.98 836.759 1400.69 811.593C1433.24 794.45 1464.5 776.541 1497.07 761.691C1512.39 754.701 1528.06 748.44 1544.27 743.083C1647.42 709.096 1768.32 718.198 1873.22 760.479C1978.3 802.83 2068.75 875.532 2139.32 963.96",
+ "M-135.18 242.841C-153.082 313.129 -97.3285 385.258 -29.5895 409.566C-23.5311 411.722 -17.4111 413.595 -11.2294 415.186C51.6571 431.362 119.045 419.051 182.184 401.718C194.338 398.36 206.518 394.808 218.654 391.238C275.715 374.43 333.262 357.048 392.853 356.44C412.123 356.248 431.111 357.789 449.716 360.996C575.674 382.612 682.041 478.429 770.366 574.313C776.778 581.298 783.19 588.283 789.615 595.298C884.76 699.2 985.927 799.377 1110.02 840.618C1151.2 854.299 1193.13 866.998 1239.93 863.139C1295.46 858.635 1349.77 833.048 1397.92 806.083C1430.78 787.707 1462.08 768.353 1494.9 752.116C1510.35 744.485 1526.11 737.595 1542.55 731.664C1647.09 694.003 1771.9 702.56 1879.35 746.344C1986.98 790.199 2078.84 865.92 2150.59 957.1",
+ "M-134.896 223.127C-152.838 293.322 -97.7516 365.518 -30.339 390.517C-24.3159 392.761 -18.2135 394.679 -12.0804 396.327C50.5724 413.153 117.863 401.726 181.14 385.14C193.33 381.949 205.501 378.547 217.66 375.114C274.787 358.974 332.423 342.139 391.935 341.858C411.2 341.741 430.123 343.384 448.741 346.622C574.625 368.746 680.544 464.719 768.021 561.186C774.372 568.198 780.735 575.24 787.081 582.327C881.117 686.889 980.631 787.483 1102.18 832.678C1143.66 848.095 1185.99 863.184 1233.93 860.008C1290.91 856.311 1346.58 829.294 1395.17 800.53C1428.3 780.935 1459.66 760.091 1492.7 742.48C1508.24 734.221 1524.17 726.678 1540.8 720.185C1646.74 678.881 1775.43 686.907 1885.45 732.15C1995.62 777.476 2088.92 856.279 2161.87 950.166",
+ "M-134.603 203.437C-152.602 273.584 -98.1348 345.79 -31.1106 371.504C-25.1051 373.793 -19.0381 375.799 -12.9536 377.504C49.4213 394.963 116.678 384.393 180.061 368.567C192.273 365.513 204.467 362.248 216.647 358.952C273.842 343.479 331.536 327.205 390.999 327.238C410.243 327.24 429.147 328.927 447.731 332.254C573.557 354.842 678.999 450.983 765.672 548.053C771.961 555.091 778.245 562.204 784.529 569.318C877.486 674.526 975.321 775.733 1094.31 824.7C1136.08 841.898 1178.81 859.345 1227.95 856.857C1286.39 853.996 1343.43 825.551 1392.47 794.944C1425.91 774.084 1457.32 751.827 1490.6 732.828C1506.23 723.91 1522.32 715.744 1539.19 708.676C1646.52 663.699 1779.12 671.18 1891.69 717.926C2004.39 764.724 2099.14 846.565 2173.28 943.203",
+ "M-134.306 183.756C-152.345 253.81 -98.5322 326.114 -31.892 352.469C-25.9351 354.816 -19.9166 356.879 -13.8055 358.646C48.3357 376.755 115.527 367.055 179.017 351.989C191.22 349.085 203.436 345.957 215.639 342.798C272.887 327.961 330.696 312.297 390.067 312.626C409.275 312.717 428.145 314.492 446.724 317.893C572.493 340.946 677.458 437.256 763.296 534.941C769.536 542.037 775.758 549.176 781.949 556.33C873.829 662.184 969.976 764.154 1086.43 816.775C1128.51 835.783 1171.6 855.528 1221.95 853.727C1281.85 851.704 1340.24 821.799 1389.7 789.361C1423.45 767.268 1454.9 743.566 1488.4 723.192C1504.15 713.634 1520.35 704.84 1537.44 697.198C1646.17 648.578 1782.68 655.514 1897.8 703.763C2013.06 752.064 2109.22 836.925 2184.57 936.3",
+ "M-134.041 164.084C-152.138 234.09 -98.9741 306.417 -32.6604 333.462C-26.7389 335.897 -20.738 338.005 -14.6755 339.829C47.201 358.601 114.344 349.728 177.91 335.434C190.135 332.668 202.387 329.708 214.581 326.698C271.896 312.529 329.794 297.413 389.117 298.055C408.303 298.265 427.155 300.085 445.73 303.562C571.455 327.109 675.912 423.601 760.933 521.857C767.111 528.979 773.253 536.19 779.396 543.401C870.197 649.902 964.59 752.736 1078.56 808.877C1120.92 829.741 1164.41 851.77 1215.95 850.669C1277.29 849.453 1337.05 818.119 1386.95 783.882C1420.98 760.57 1452.49 735.409 1486.21 713.661C1502.05 703.445 1518.41 694.027 1535.73 685.81C1645.87 633.547 1786.28 639.938 1903.94 689.659C2021.74 739.433 2119.32 827.345 2195.88 929.458",
+ "M-133.759 144.37C-151.895 214.283 -99.3683 286.664 -33.443 314.426C-27.539 316.905 -21.5734 319.101 -15.5153 321C46.0966 340.435 113.205 332.42 176.878 318.886C189.139 316.287 201.368 313.446 213.585 310.574C270.967 297.071 328.923 282.516 388.197 283.472C407.348 283.771 426.208 285.697 444.735 289.231C570.403 313.243 674.383 409.903 758.568 508.774C764.698 515.954 770.778 523.192 776.828 530.442C866.565 637.621 959.15 741.452 1070.7 800.982C1113.35 823.731 1157.24 847.969 1209.96 847.569C1272.76 847.19 1333.87 814.396 1384.23 778.347C1418.58 753.801 1450.15 727.152 1484.09 704.06C1500.06 693.203 1516.55 683.144 1534.07 674.366C1645.6 618.429 1789.92 624.276 1910.13 675.5C2030.48 726.776 2129.47 817.709 2207.22 922.572",
+ "M-133.463 124.681C-151.657 194.545 -99.7797 266.949 -34.1809 295.401C-28.3256 297.937 -22.3777 300.178 -16.3548 302.166C45.0101 322.22 112.053 315.075 175.833 302.3C188.116 299.839 200.35 297.179 212.575 294.413C270.024 281.577 328.083 267.601 387.264 268.853C406.38 269.241 425.205 271.254 443.727 274.864C569.307 299.353 672.854 396.199 756.192 495.655C762.228 502.875 768.26 510.17 774.248 517.447C862.907 625.273 953.65 730.188 1062.83 793.004C1105.74 817.698 1150.06 844.13 1203.99 844.418C1268.25 844.877 1330.71 810.622 1381.5 772.744C1416.11 746.947 1447.76 718.87 1481.92 694.404C1497.99 682.919 1514.62 672.251 1532.36 662.867C1645.28 603.287 1793.51 608.589 1916.27 661.285C2039.15 714.034 2139.56 808.017 2218.52 915.618",
+ "M-133.197 105.016C-151.431 174.787 -100.221 247.258 -34.9931 276.382C-29.1863 278.976 -23.2428 281.291 -17.2685 283.337C43.8318 304.054 110.84 297.766 174.727 285.752C187.001 283.441 199.288 280.904 211.549 278.306C269.083 266.093 327.212 252.709 386.315 254.288C405.408 254.795 424.216 256.853 442.72 260.506C568.243 285.459 671.313 382.474 753.846 482.532C759.834 489.81 765.805 497.131 771.7 504.448C859.28 612.921 948.159 719.04 1054.98 785.068C1098.15 811.736 1142.87 840.302 1197.98 841.291C1263.7 842.556 1327.49 806.885 1378.74 767.195C1413.67 740.165 1445.36 710.643 1479.77 684.789C1495.91 672.646 1512.72 661.354 1530.68 651.396C1645.01 588.173 1797.14 592.899 1922.44 647.098C2047.88 701.35 2149.7 798.353 2229.87 908.692",
+ "M-132.9 85.3296C-151.192 155.053 -100.601 227.534 -35.7616 257.374C-29.9591 260.043 -24.0641 262.416 -18.1074 264.506C42.7591 285.873 109.689 280.424 173.664 269.214C185.961 267.04 198.239 264.653 210.522 262.192C268.123 250.646 326.31 237.823 385.364 239.716C404.423 240.311 423.195 242.458 441.695 246.186C567.174 271.634 669.767 368.818 751.452 469.46C757.378 476.764 763.255 484.126 769.115 491.531C855.618 600.65 942.535 708.09 1047.09 777.182C1090.46 805.852 1135.66 836.556 1191.98 838.232C1259.15 840.334 1324.29 803.204 1375.98 761.714C1411.19 733.465 1442.95 702.485 1477.57 675.256C1493.85 662.472 1510.75 650.553 1528.95 640.019C1644.66 573.123 1800.71 577.336 1928.55 633.007C2056.53 688.73 2159.77 788.785 2241.16 901.861",
+ "M-132.619 65.6142C-150.95 135.244 -101.014 207.824 -36.5137 238.322C-30.7599 241.049 -24.9134 243.479 -18.9611 245.645C41.6408 267.675 108.522 263.052 172.605 252.602C184.937 250.596 197.238 248.346 209.512 246.035C267.18 235.157 325.469 222.912 384.431 225.101C403.467 225.816 422.222 228.006 440.686 231.823C566.109 257.735 668.223 355.087 749.074 456.345C754.951 463.707 760.767 471.095 766.534 478.54C851.958 588.306 936.883 697.078 1039.2 769.254C1082.76 799.969 1128.47 832.722 1185.98 835.099C1254.61 838.039 1321.1 799.448 1373.26 756.147C1408.78 726.663 1440.57 694.208 1475.42 665.636C1491.77 652.193 1508.85 639.651 1527.24 628.556C1644.36 558.017 1804.3 561.654 1934.7 618.828C2065.23 676.054 2169.88 779.129 2252.48 894.943",
+ "M-132.324 45.9289C-150.682 115.497 -101.427 188.113 -37.2975 219.284C-31.5612 222.055 -25.75 224.574 -19.8154 226.783C40.5086 249.445 107.369 245.711 171.558 236.02C183.912 234.151 196.205 232.052 208.501 229.878C266.236 219.666 324.614 207.969 383.496 210.486C402.497 211.289 421.248 213.554 439.708 217.447C565.073 243.822 666.711 341.343 746.726 443.217C752.542 450.605 758.278 458.063 763.983 465.535C848.33 575.948 931.151 686.137 1031.34 761.281C1075.06 794.085 1121.29 828.888 1179.96 831.935C1250.04 835.681 1317.9 795.661 1370.48 750.53C1406.28 719.827 1438.13 685.913 1473.23 655.953C1489.72 641.87 1506.92 628.687 1525.54 617.017C1644.05 542.804 1807.91 545.927 1940.85 604.573C2073.91 663.271 2179.98 769.397 2263.77 887.962",
+ "M-132.058 26.2597C-150.486 95.7487 -101.836 168.405 -38.0645 200.279C-32.3635 203.138 -26.5701 205.701 -20.684 207.968C39.4063 231.28 106.188 228.386 170.484 219.455C182.829 217.736 195.188 215.791 207.463 213.736C265.264 204.192 323.701 193.056 382.565 195.873C401.531 196.765 420.26 199.15 438.702 203.086C563.993 229.97 665.184 327.646 744.351 430.104C750.118 437.55 755.792 445.035 761.405 452.547C844.673 563.606 925.387 675.288 1023.46 753.355C1067.32 788.262 1114.08 825.07 1173.97 828.836C1245.51 833.419 1314.74 791.97 1367.74 745.009C1403.84 713.042 1435.78 677.701 1471.04 646.349C1487.63 631.638 1504.96 617.814 1523.81 605.569C1643.75 527.7 1811.47 530.261 1946.97 590.441C2082.58 650.611 2190.08 759.788 2275.07 881.091",
+ "M-131.761 6.57552C-150.217 76.0027 -102.247 148.695 -38.833 181.272C-33.1807 184.189 -27.4048 186.796 -21.554 189.152C38.2716 213.127 105.019 211.09 169.421 202.919C181.789 201.336 194.139 199.542 206.48 197.642C264.335 188.734 322.887 178.207 381.673 181.351C400.616 182.362 419.327 184.791 437.721 188.785C562.955 216.133 663.638 313.991 742.032 417.038C747.706 424.523 753.363 432.053 758.926 439.622C841.117 551.328 919.617 664.51 1015.67 745.461C1059.6 782.499 1106.97 821.316 1168.06 825.738C1241.06 831.159 1311.63 788.25 1365.07 739.489C1401.49 706.289 1433.46 669.503 1468.94 636.777C1485.64 621.394 1503.11 606.96 1522.19 594.141C1643.54 512.629 1815.17 514.645 1953.21 576.297C2091.37 637.97 2200.3 750.154 2286.48 874.208",
+ "M-131.479 -13.1409C-150.006 56.2069 -102.673 128.953 -39.6158 162.234C-33.9811 165.195 -28.2406 167.89 -22.4074 170.29C37.1712 194.884 103.853 193.717 168.345 186.35C180.748 184.936 193.107 183.248 205.439 181.498C263.361 173.257 322.002 163.278 380.708 166.749C399.617 167.848 418.292 170.366 436.682 174.435C561.858 202.247 662.077 300.304 739.623 403.936C745.249 411.479 750.812 419.048 756.314 426.644C837.396 539.01 913.652 653.707 1007.74 737.515C1051.74 776.682 1099.74 817.464 1162 822.631C1236.44 828.858 1308.38 784.52 1362.27 733.917C1398.97 699.497 1431.01 661.253 1466.74 627.139C1483.54 611.128 1501.16 596.04 1520.44 582.66C1643.18 497.474 1818.72 498.945 1959.31 562.1C2100.01 625.246 2210.37 740.511 2297.76 867.272",
+ "M-131.183 -32.8251C-149.736 36.4608 -103.04 109.261 -40.367 143.183C-34.7809 146.201 -29.0446 148.972 -23.2601 151.429C36.0539 176.686 102.701 176.377 167.286 169.739C179.712 168.461 192.075 166.954 204.43 165.341C262.45 157.754 321.117 148.349 379.775 152.134C398.662 153.353 417.32 155.915 435.705 160.059C560.838 188.366 660.566 286.561 737.277 390.808C742.841 398.377 748.356 406.004 753.765 413.64C833.782 526.683 907.701 642.934 999.895 729.573C1043.92 770.927 1092.57 813.661 1156.02 819.485C1231.93 826.55 1305.22 780.751 1359.55 728.349C1396.56 692.696 1428.63 652.976 1464.59 617.518C1481.47 600.88 1499.23 585.151 1518.74 571.196C1642.88 482.368 1822.29 483.307 1965.45 547.921C2108.71 612.569 2220.48 730.855 2309.08 860.353",
+ "M-130.918 -52.4957C-149.541 16.7107 -103.481 89.5652 -41.166 124.19C-35.5842 127.283 -29.9098 130.081 -24.1606 132.626C34.8888 158.546 101.488 159.063 166.193 153.216C178.61 152.089 191.027 150.705 203.373 149.242C261.459 142.322 320.216 133.466 378.795 137.578C397.646 138.884 416.299 141.521 434.649 145.754C559.725 174.525 658.99 272.92 734.852 377.751C740.367 385.378 745.79 393.045 751.137 400.707C830.076 514.397 901.565 632.242 991.953 721.672C1035.96 765.195 1085.29 809.868 1149.97 816.41C1227.37 824.299 1301.98 777.054 1356.74 722.853C1394.02 685.948 1426.18 644.801 1462.38 607.956C1479.38 590.646 1497.28 574.307 1517.02 559.777C1642.56 467.306 1825.87 467.67 1971.58 533.786C2117.37 599.907 2230.57 721.244 2320.35 853.493",
+ "M-130.622 -72.1836C-149.272 -3.03889 -103.893 69.8518 -41.9042 105.166C-36.371 108.317 -30.7319 111.203 -24.9693 113.779C33.8464 140.35 100.38 141.737 165.179 136.619C177.618 135.628 190.039 134.426 202.394 133.069C260.534 126.785 319.407 118.538 377.893 122.946C396.722 124.372 415.327 127.067 433.672 131.375C558.66 160.623 657.478 259.173 732.506 364.619C737.959 372.273 743.333 379.997 748.601 387.731C826.461 502.067 895.507 621.476 984.117 713.758C1028.05 759.508 1078.14 806.094 1143.99 813.305C1222.82 822.001 1298.8 773.327 1354.03 717.313C1391.62 679.176 1423.82 636.584 1460.24 598.364C1477.34 580.427 1495.38 563.478 1515.33 548.342C1642.26 452.197 1829.49 452.047 1977.74 519.636C2126.05 587.272 2240.69 711.616 2331.68 846.603",
+ "M-130.339 -91.8958C-149.06 -22.8305 -104.286 50.1008 -42.6992 86.1005C-37.2145 89.3091 -31.5798 92.27 -25.8658 94.9039C32.6719 122.107 99.1708 124.351 164.059 120.037C176.52 119.183 188.964 118.118 201.354 116.929C259.561 111.312 318.492 103.626 376.929 108.348C395.723 109.863 414.324 112.632 432.665 117.015C557.609 146.758 655.937 245.446 730.129 351.508C735.534 359.219 740.815 366.983 746.021 374.743C822.803 489.726 889.313 610.738 976.254 705.788C1020.11 753.735 1070.99 802.25 1138.02 810.162C1218.31 819.695 1295.64 769.561 1351.3 711.717C1389.17 672.36 1421.43 628.31 1458.07 588.716C1475.28 570.107 1493.46 552.548 1513.64 536.838C1641.98 437.05 1833.1 436.324 1983.9 505.416C2134.75 574.525 2250.81 701.919 2343.02 839.644",
+ "M-130.042 -111.579C-148.79 -42.5757 -104.697 30.3919 -43.4367 67.0813C-37.9564 70.3651 -32.3835 73.3526 -26.6606 76.0925C31.6434 103.945 98.0768 107.06 163.072 103.505C175.538 102.833 187.99 101.874 200.402 100.822C258.677 95.8719 317.696 88.7338 376.085 93.7694C394.844 95.3724 413.422 98.2614 431.733 102.657C556.62 132.865 654.483 231.752 727.859 338.385C733.201 346.123 738.421 353.913 743.547 361.744C819.251 477.374 883.181 599.972 968.48 697.852C1012.2 748.052 1063.88 798.422 1132.12 807.022C1213.88 817.392 1292.56 765.797 1348.65 706.155C1386.83 665.565 1419.15 620.025 1456.02 579.088C1473.33 559.851 1491.67 541.638 1512.05 525.366C1641.77 421.905 1836.81 420.665 1990.2 491.246C2143.59 561.827 2261.07 692.273 2354.49 832.735",
+ "M-129.779 -131.252C-148.597 -62.3275 -105.097 10.7117 -44.2378 48.0866C-38.8061 51.4278 -33.2376 54.4906 -27.5632 57.288C30.4762 85.8036 96.8616 89.745 161.963 86.9501C174.451 86.4149 186.939 85.6235 199.33 84.6908C257.671 80.408 316.792 73.8486 375.089 79.1804C393.826 80.9027 412.387 83.8358 430.662 88.3203C555.492 118.992 652.878 218.047 725.418 325.296C730.682 333.104 735.839 340.922 740.917 348.81C815.543 465.087 876.848 589.252 960.536 689.949C1004.11 742.372 1056.61 794.658 1126.04 803.959C1209.24 815.135 1289.29 762.112 1345.81 700.671C1384.28 658.86 1416.67 611.863 1453.75 569.551C1471.15 549.687 1489.62 530.833 1510.23 513.986C1641.36 406.882 1840.31 405.098 1996.23 477.151C2152.17 549.235 2271.06 682.701 2365.7 825.9",
+ "M-129.482 -150.938C-148.327 -82.0763 -105.508 -9.00068 -45.0062 29.0772C-39.5922 32.4627 -34.059 35.6136 -28.4332 38.4685C29.3591 67.6031 95.6791 72.415 160.901 70.411C173.411 70.0127 185.89 69.3715 198.316 68.6066C256.724 64.991 315.904 58.9926 374.152 64.6381C392.854 66.4489 411.41 69.4572 429.681 74.0169C554.454 105.152 651.345 204.421 723.068 312.24C728.27 320.075 733.378 327.95 738.363 335.879C811.912 452.802 870.517 578.531 952.682 682.08C996.055 736.752 1049.46 790.884 1120.06 800.886C1204.73 812.899 1286.14 758.447 1343.1 695.132C1381.87 652.057 1414.31 603.646 1451.63 559.946C1469.16 539.41 1487.76 519.946 1508.6 502.525C1641.13 391.778 1843.97 389.418 2002.45 462.974C2160.93 536.53 2281.24 673.047 2377.09 818.984",
+ "M-129.2 -170.657C-148.116 -101.874 -105.933 -28.7449 -45.7713 9.99186C-40.4058 13.4348 -34.8902 16.6302 -29.2688 19.5603C28.259 49.358 94.5443 55.0271 159.86 53.7519C172.392 53.4905 184.907 53.0172 197.311 52.3716C255.804 49.3788 315.054 43.9724 373.223 49.945C391.903 51.8751 410.411 54.941 428.677 59.5757C553.375 91.2193 649.807 190.612 720.695 299.047C725.848 306.94 730.864 314.854 735.787 322.809C808.257 440.379 864.119 567.654 944.792 674.042C987.96 730.964 1042.25 786.985 1114.06 797.674C1200.19 810.525 1282.95 754.613 1340.35 689.499C1379.43 645.191 1411.91 595.335 1449.45 550.26C1467.07 529.097 1485.83 508.979 1506.87 490.996C1640.79 376.575 1847.55 373.701 2008.57 448.73C2169.6 523.788 2291.32 663.326 2388.35 812.014",
+ "M-128.936 -190.323C-147.878 -121.602 -106.345 -48.4495 -46.5712 -8.99638C-41.241 -5.46501 -35.7431 -2.22561 -30.1703 0.761936C27.0928 31.2228 93.3303 37.7183 158.735 37.2472C171.272 37.167 183.796 36.7997 196.266 36.3087C254.826 33.983 314.178 29.1552 372.255 35.424C390.899 37.4425 409.403 40.5835 427.634 45.3067C552.275 77.4143 648.243 177.007 718.282 286.026C723.374 293.946 728.341 301.918 733.171 309.913C804.563 428.129 857.637 556.933 936.876 666.208C979.763 725.375 1035 783.259 1108 794.649C1195.57 808.307 1279.69 750.965 1337.53 684.052C1376.89 638.524 1409.44 587.21 1447.18 540.73C1464.93 518.926 1483.79 498.18 1505.06 479.623C1640.38 361.559 1851.04 358.11 2014.61 434.641C2178.18 511.172 2301.32 653.76 2399.56 805.186",
+ "M-128.638 -210.011C-147.62 -141.382 -106.754 -68.1626 -47.3073 -28.0197C-41.9947 -24.4441 -36.563 -21.1029 -30.9769 -18.0844C26.0525 13.0263 92.2246 20.3924 157.723 20.6501C170.282 20.7069 182.828 20.4763 195.289 20.1355C253.916 18.4769 313.327 14.2103 371.355 20.7929C389.995 22.8865 408.432 26.1292 426.677 30.8832C551.261 63.4549 646.751 163.216 715.987 272.837C721.029 280.814 725.904 288.826 730.686 296.879C801.013 415.773 851.272 546.043 929.077 658.206C971.683 719.617 1027.88 779.396 1102.09 791.473C1191.12 805.968 1276.6 747.166 1334.87 678.454C1374.54 631.693 1407.12 578.903 1445.12 531.067C1462.95 508.604 1481.98 487.235 1503.48 468.103C1640.2 346.396 1854.77 342.402 2020.88 420.405C2187 498.439 2311.58 644.034 2411.01 798.211",
+ ];
+ return (
+
+
+ {/* */}
+ {paths.map((path, i) => (
+
+ ))}
+
+ {paths.map((path, index) => (
+
+ ))}
+
+ {paths.map((path, index) => (
+
+
+
+
+
+
+ ))}
+
+
+
+
+
+
+
+
+
+ );
+});
+
+BackgroundBeams.displayName = "BackgroundBeams";
diff --git a/documentation/src/components/landing/hero/hero.tsx b/documentation/src/components/landing/hero/hero.tsx
new file mode 100644
index 000000000..cec32a3a5
--- /dev/null
+++ b/documentation/src/components/landing/hero/hero.tsx
@@ -0,0 +1,77 @@
+/* eslint-disable react/no-array-index-key */
+/* eslint-disable jsx-a11y/anchor-is-valid */
+import { Particles } from "@site/src/components/particles";
+import { Description, Title } from "@site/src/components";
+import Link from "@docusaurus/Link";
+import { useWindowSize } from "@reins/hooks";
+import { ArrowRight, Download, Sparkles } from "lucide-react";
+
+import { Paths } from "./paths/paths";
+
+export const Hero = () => {
+ const [width] = useWindowSize();
+
+ return (
+
+ {/* Illustrations */}
+
+
+
+
+
+
+
+
+ {/* Particles animation */}
+ 767 ? 40 : 30} />
+
+ {/* Hero content */}
+
+
+
+
+ Now with dedicated devtools
+
+ →
+
+
+
+
+ Connect to any API.
+ Simply, TypeSafe, Fast.
+
+
+ Hyper Fetch is a framework that makes it easy to connect your frontends to the server data. Using{" "}
+
+ request
+ {" "}
+ based or{" "}
+
+ real-time
+ {" "}
+ connection.
+
+
+
+ Get Started
+
+
+
Download HyperFlow
+
+
+
+
+ );
+};
diff --git a/documentation/src/components/landing/hero/index.ts b/documentation/src/components/landing/hero/index.ts
new file mode 100644
index 000000000..5e2d3caf3
--- /dev/null
+++ b/documentation/src/components/landing/hero/index.ts
@@ -0,0 +1 @@
+export * from "./hero";
diff --git a/documentation/src/components/landing/hero/paths/animations/animation.types.ts b/documentation/src/components/landing/hero/paths/animations/animation.types.ts
new file mode 100644
index 000000000..3c7820353
--- /dev/null
+++ b/documentation/src/components/landing/hero/paths/animations/animation.types.ts
@@ -0,0 +1,15 @@
+export type Animation = (options: {
+ // IDS
+ path: string;
+ item: string;
+ dot: string;
+ glow: string;
+ label: string;
+ // Settings
+ timeline: gsap.core.Timeline;
+ delay: number;
+ duration: number;
+ // Other
+ pathIndex: number;
+ index: number;
+}) => void;
diff --git a/documentation/src/components/landing/hero/paths/animations/dot.animation.ts b/documentation/src/components/landing/hero/paths/animations/dot.animation.ts
new file mode 100644
index 000000000..5a4abce3b
--- /dev/null
+++ b/documentation/src/components/landing/hero/paths/animations/dot.animation.ts
@@ -0,0 +1,44 @@
+import { Animation } from "./animation.types";
+
+export const dotAnimation: Animation = ({ dot, timeline }) => {
+ timeline.from(
+ dot,
+ {
+ opacity: 0,
+ scale: 0,
+ },
+ 0,
+ );
+ timeline.to(
+ dot,
+ {
+ opacity: 1,
+ scale: 1,
+ },
+ 1,
+ );
+ timeline.to(
+ dot,
+ {
+ opacity: 1,
+ scale: 1,
+ },
+ 5,
+ );
+ timeline.to(
+ dot,
+ {
+ opacity: 1,
+ scale: 1,
+ },
+ 8.5,
+ );
+ timeline.to(
+ dot,
+ {
+ opacity: 0,
+ scale: 0,
+ },
+ 9.5,
+ );
+};
diff --git a/documentation/src/components/landing/hero/paths/animations/glow.animation.ts b/documentation/src/components/landing/hero/paths/animations/glow.animation.ts
new file mode 100644
index 000000000..7dfa09d5d
--- /dev/null
+++ b/documentation/src/components/landing/hero/paths/animations/glow.animation.ts
@@ -0,0 +1,73 @@
+import { Animation } from "./animation.types";
+
+export const glowAnimation: Animation = ({ timeline, index }) => {
+ const halo = `#halo${index}`;
+ const gradient = `#gradient${index}`;
+
+ // Halo
+ timeline.from(
+ halo,
+ {
+ opacity: 0,
+ scale: 0,
+ },
+ 0,
+ );
+ timeline.to(
+ halo,
+ {
+ opacity: 1,
+ scale: 1,
+ },
+ 1,
+ );
+ timeline.to(
+ halo,
+ {
+ opacity: 1,
+ scale: 1,
+ },
+ 8,
+ );
+ timeline.to(
+ halo,
+ {
+ opacity: 0,
+ scale: 0,
+ },
+ 9.7,
+ );
+ // Gradient
+ timeline.from(
+ gradient,
+ {
+ opacity: 0,
+ scale: 0,
+ },
+ 0,
+ );
+ timeline.to(
+ gradient,
+ {
+ opacity: 1,
+ scale: 1,
+ },
+ 1,
+ );
+ timeline.to(
+ gradient,
+ {
+ opacity: 1,
+ scale: 1,
+ },
+ 8,
+ );
+ timeline.to(
+ gradient,
+ {
+ opacity: 0,
+ scale: 0,
+ },
+ 9.7,
+ );
+};
diff --git a/documentation/src/components/landing/hero/paths/animations/label.animation.ts b/documentation/src/components/landing/hero/paths/animations/label.animation.ts
new file mode 100644
index 000000000..78d2586e9
--- /dev/null
+++ b/documentation/src/components/landing/hero/paths/animations/label.animation.ts
@@ -0,0 +1,39 @@
+import { Animation } from "./animation.types";
+
+export const labelAnimation: Animation = ({ label, timeline }) => {
+ timeline.from(
+ label,
+ {
+ opacity: 0,
+ },
+ 0,
+ );
+ timeline.to(
+ label,
+ {
+ opacity: 0,
+ },
+ 5,
+ );
+ timeline.to(
+ label,
+ {
+ opacity: 1,
+ },
+ 7,
+ );
+ timeline.to(
+ label,
+ {
+ opacity: 1,
+ },
+ 7,
+ );
+ timeline.to(
+ label,
+ {
+ opacity: 0,
+ },
+ 9,
+ );
+};
diff --git a/documentation/src/components/landing/hero/paths/dot/dot.tsx b/documentation/src/components/landing/hero/paths/dot/dot.tsx
new file mode 100644
index 000000000..b806d0d50
--- /dev/null
+++ b/documentation/src/components/landing/hero/paths/dot/dot.tsx
@@ -0,0 +1,101 @@
+import { useLayoutEffect } from "react";
+import { useWindowSize } from "@reins/hooks";
+
+import { Animation } from "../animations/animation.types";
+import { dotAnimation } from "../animations/dot.animation";
+// import { labelAnimation } from "../animations/label.animation";
+// import { glowAnimation } from "../animations/glow.animation";
+
+function getMatrix(element: HTMLDivElement) {
+ const { transform } = element.style;
+ const re = /translate3d\((?.*?)px, (?.*?)px, (?.*?)px/;
+ const results = re.exec(transform);
+
+ if (!results) {
+ return {
+ x: 0,
+ y: 0,
+ z: 0,
+ };
+ }
+
+ return {
+ x: results.groups.x as unknown as number,
+ y: results.groups.y as unknown as number,
+ z: results.groups.z as unknown as number,
+ };
+}
+
+export const Dot = ({
+ id,
+ tool,
+ animation,
+}: {
+ id: number;
+ tool: { name: string; dotClassName: string };
+ animation: Parameters[0];
+}) => {
+ const [width] = useWindowSize();
+
+ useLayoutEffect(() => {
+ animation.timeline.set(animation.item, { xPercent: -50, yPercent: -50, transformOrigin: "50% 50%" });
+ animation.timeline.to(animation.item, {
+ motionPath: {
+ path: animation.path,
+ align: animation.path,
+ autoRotate: true,
+ start: 0,
+ end: 1,
+ },
+ duration: animation.duration,
+ // TOO SLOW
+ // onUpdate: () => {
+ // const item = document.querySelector(animation.item) as HTMLDivElement;
+ // const gradient = document.querySelector(`#gradient${animation.index}`) as SVGPathElement;
+ // const halo = document.querySelector(`#halo${animation.index}`) as SVGPathElement;
+ // const paths = document.querySelector(`#paths`) as SVGElement;
+ // const element = document.querySelector(animation.path) as SVGPathElement;
+
+ // if (!item || !gradient || !halo || !element || !paths) {
+ // return;
+ // }
+
+ // const { x, y } = getMatrix(item);
+
+ // const svgViewportWidth = 2000;
+ // const svgViewportHeight = 1000;
+ // const svgWidth = paths.getBoundingClientRect().width;
+ // const svgHeight = paths.getBoundingClientRect().height;
+ // const topOffset = 185;
+ // const leftOffset = -5;
+ // const scaleX = svgViewportWidth / svgWidth;
+ // const scaleY = svgViewportHeight / svgHeight;
+
+ // halo.setAttribute("cx", `${x * scaleX + leftOffset}`);
+ // halo.setAttribute("cy", `${y * scaleY + topOffset}`);
+
+ // gradient.setAttribute("cx", `${x * scaleX + leftOffset}`);
+ // gradient.setAttribute("cy", `${y * scaleY + topOffset}`);
+ // },
+ });
+
+ dotAnimation(animation);
+ // labelAnimation(animation);
+ // glowAnimation(animation);
+ }, [animation, id, width]);
+
+ return (
+
+ );
+};
diff --git a/documentation/src/components/landing/hero/paths/glow/glow.tsx b/documentation/src/components/landing/hero/paths/glow/glow.tsx
new file mode 100644
index 000000000..23fbcb13a
--- /dev/null
+++ b/documentation/src/components/landing/hero/paths/glow/glow.tsx
@@ -0,0 +1,17 @@
+export const Glow = ({ id, path, pathIndex }: { id: number; path: string; pathIndex: number }) => {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/documentation/src/components/landing/hero/paths/paths.tsx b/documentation/src/components/landing/hero/paths/paths.tsx
new file mode 100644
index 000000000..f677d25d4
--- /dev/null
+++ b/documentation/src/components/landing/hero/paths/paths.tsx
@@ -0,0 +1,267 @@
+/* eslint-disable react/no-array-index-key */
+import { gsap } from "gsap";
+import { useIsMounted, useWindowSize } from "@reins/hooks";
+import { MotionPathPlugin } from "gsap/dist/MotionPathPlugin";
+import { useCallback, useLayoutEffect, useState } from "react";
+
+import { Animation } from "./animations/animation.types";
+import { Glow } from "./glow/glow";
+import { Dot } from "./dot/dot";
+
+const tools: Array<{ name: string; dotClassName: string }> = [
+ {
+ name: "form data",
+ dotClassName: "bg-yellow-500 shadow-neon shadow-yellow-500",
+ },
+ {
+ name: "rest",
+ dotClassName: "bg-yellow-500 shadow-neon shadow-yellow-500",
+ },
+ {
+ name: "websockets",
+ dotClassName: "bg-yellow-500 shadow-neon shadow-yellow-500",
+ },
+ {
+ name: "sse",
+ dotClassName: "bg-yellow-500 shadow-neon shadow-yellow-500",
+ },
+ {
+ name: "firebase",
+ dotClassName: "bg-yellow-500 shadow-neon shadow-yellow-500",
+ },
+ {
+ name: "realtime",
+ dotClassName: "bg-yellow-500 shadow-neon shadow-yellow-500",
+ },
+ {
+ name: "upload",
+ dotClassName: "bg-yellow-500 shadow-neon shadow-yellow-500",
+ },
+ {
+ name: "download",
+ dotClassName: "bg-yellow-500 shadow-neon shadow-yellow-500",
+ },
+ {
+ name: "stream",
+ dotClassName: "bg-yellow-500 shadow-neon shadow-yellow-500",
+ },
+ {
+ name: "form data",
+ dotClassName: "bg-yellow-500 shadow-neon shadow-yellow-500",
+ },
+ {
+ name: "rest",
+ dotClassName: "bg-yellow-500 shadow-neon shadow-yellow-500",
+ },
+ {
+ name: "websockets",
+ dotClassName: "bg-yellow-500 shadow-neon shadow-yellow-500",
+ },
+ {
+ name: "sse",
+ dotClassName: "bg-yellow-500 shadow-neon shadow-yellow-500",
+ },
+ {
+ name: "firebase",
+ dotClassName: "bg-yellow-500 shadow-neon shadow-yellow-500",
+ },
+];
+
+const paths = [
+ "M-137.178 380.636C-154.748 451.441 -94.4807 523.24 -24.1997 542.72C46.0946 562.231 121.053 542.636 189.627 517.656C258.214 492.706 326.535 461.938 399.408 458.549C550.233 451.563 678.856 560.701 786.951 665.993C895.046 771.285 1014.48 886.316 1165.16 896.055C1283.3 903.672 1394.25 843.843 1510.08 819.311C1712.27 776.47 1935 850.273 2071.41 1005.39",
+ "M-136.881 360.952C-154.491 431.664 -94.8608 503.517 -24.9372 523.7C-18.6934 525.52 -12.3837 526.982 -6.06092 528.219C58.3782 540.505 126.062 523.086 188.564 501.119C200.633 496.882 212.698 492.464 224.763 488.045C281.404 467.28 338.47 446.478 398.471 444.009C417.913 443.194 437.016 444.319 455.736 447.111C582.04 465.868 691.257 560.643 784.57 652.953C791.344 659.673 798.162 666.409 805.025 673.164C906.625 773.155 1018.39 874.014 1157.24 888.215C1196.96 892.271 1236.28 889.867 1275.9 881.843C1322.67 872.39 1368.88 855.488 1414.4 839.391C1445.49 828.406 1476.43 817.774 1507.92 809.766C1522.72 806.002 1537.68 802.865 1552.79 800.4C1648.94 784.658 1750.32 796.514 1842.48 831.343C1934.87 866.259 2018.21 923.78 2082.74 998.507",
+ "M-136.585 341.267C-154.253 411.93 -95.272 483.806 -25.7059 504.692C-19.4798 506.556 -13.2054 508.107 -6.90021 509.388C57.261 522.306 124.91 505.745 187.533 484.568C199.624 480.468 211.68 476.2 223.767 471.918C280.475 451.82 337.63 431.566 397.552 429.424C416.971 428.729 436.057 429.898 454.772 432.765C581.033 452.017 689.772 546.96 782.237 639.855C788.95 646.601 795.72 653.395 802.49 660.19C903.012 760.827 1012.87 861.186 1149.43 880.259C1189.32 885.848 1229.14 886.05 1269.94 878.727C1318.16 870.08 1365.73 851.749 1411.69 833.854C1443.06 821.648 1474.07 809.558 1505.78 800.176C1520.71 795.771 1535.76 792.006 1551.1 788.966C1648.65 769.581 1753.94 780.893 1848.66 817.224C1943.58 853.613 2028.34 914.185 2094.06 991.663",
+ "M-136.321 321.595C-154.028 392.165 -95.7151 464.109 -26.4888 485.654C-20.3113 487.576 -14.0721 489.215 -7.7846 490.54C56.1429 504.108 123.726 488.417 186.456 468C198.538 464.05 210.661 459.937 222.739 455.806C279.514 436.374 336.727 416.682 396.6 414.853C415.985 414.246 435.035 415.504 453.733 418.415C579.906 438.144 688.199 533.243 779.828 626.753C786.492 633.557 793.169 640.391 799.877 647.212C899.335 748.527 1007.36 848.464 1141.51 872.344C1181.64 879.483 1221.9 882.243 1263.91 875.607C1313.58 867.798 1362.51 848.007 1408.89 828.281C1440.57 814.843 1471.61 801.277 1503.54 790.551C1518.56 785.488 1533.79 781.1 1549.32 777.498C1648.27 754.471 1757.46 765.207 1854.72 803.041C1952.2 840.932 2038.37 904.525 2105.3 984.74",
+ "M-136.038 301.881C-153.772 372.39 -96.1084 444.357 -27.2704 466.618C-21.0973 468.614 -14.92 470.28 -8.66779 471.694C54.995 485.925 122.531 471.06 185.367 451.403C197.485 447.621 209.585 443.627 221.717 439.619C278.559 420.855 335.874 401.741 395.686 400.196C415.048 399.708 434.081 401.01 452.743 404.009C578.859 424.203 686.657 519.514 777.501 613.582C784.103 620.412 790.731 627.304 797.36 634.196C895.739 736.157 1002 835.903 1133.68 864.359C1174.02 873.093 1214.78 878.384 1257.95 872.418C1309.12 865.433 1359.37 844.195 1406.19 822.671C1438.14 807.981 1469.26 792.988 1501.44 780.875C1516.54 775.184 1531.95 770.173 1547.69 765.965C1648.04 739.264 1761.14 749.486 1860.95 788.793C1960.97 828.156 2048.56 894.799 2116.7 977.753",
+ "M-135.742 282.197C-153.546 352.626 -96.5063 424.678 -28.039 447.611C-21.9144 449.666 -15.7415 451.406 -9.50693 452.864C53.8912 467.759 121.379 453.72 184.335 434.854C196.476 431.209 208.598 427.351 220.721 423.494C277.63 405.397 335.034 386.831 394.766 385.612C414.093 385.213 433.091 386.603 451.78 389.664C577.852 410.353 685.159 505.802 775.168 600.485C781.721 607.373 788.244 614.274 794.824 621.223C892.125 723.831 996.651 823.552 1125.85 856.449C1166.46 866.781 1207.61 874.582 1251.98 869.347C1304.59 863.168 1356.2 840.502 1403.49 817.165C1435.75 801.242 1466.94 784.791 1499.3 771.316C1514.54 764.985 1530.04 759.346 1546.02 754.564C1647.76 724.22 1764.76 733.867 1867.12 774.676C1969.66 815.555 2058.69 885.205 2128.04 970.896",
+ "M-135.446 262.512C-153.277 332.879 -96.9175 404.967 -28.7767 428.59C-22.7007 430.702 -16.5322 432.518 -10.3462 434.033C52.805 449.547 120.24 436.409 183.259 418.286C195.422 414.777 207.549 411.101 219.694 407.381C276.657 389.92 334.132 371.946 393.816 371.041C413.121 370.761 432.114 372.227 450.755 375.345C576.77 396.498 683.613 492.146 772.774 587.414C779.265 594.328 785.739 601.287 792.226 608.276C888.449 711.531 991.309 811.383 1117.94 848.533C1158.82 860.509 1200.38 870.805 1245.95 866.227C1300.02 860.886 1352.98 836.759 1400.69 811.593C1433.24 794.45 1464.5 776.541 1497.07 761.691C1512.39 754.701 1528.06 748.44 1544.27 743.083C1647.42 709.096 1768.32 718.198 1873.22 760.479C1978.3 802.83 2068.75 875.532 2139.32 963.96",
+ "M-135.18 242.841C-153.082 313.129 -97.3285 385.258 -29.5895 409.566C-23.5311 411.722 -17.4111 413.595 -11.2294 415.186C51.6571 431.362 119.045 419.051 182.184 401.718C194.338 398.36 206.518 394.808 218.654 391.238C275.715 374.43 333.262 357.048 392.853 356.44C412.123 356.248 431.111 357.789 449.716 360.996C575.674 382.612 682.041 478.429 770.366 574.313C776.778 581.298 783.19 588.283 789.615 595.298C884.76 699.2 985.927 799.377 1110.02 840.618C1151.2 854.299 1193.13 866.998 1239.93 863.139C1295.46 858.635 1349.77 833.048 1397.92 806.083C1430.78 787.707 1462.08 768.353 1494.9 752.116C1510.35 744.485 1526.11 737.595 1542.55 731.664C1647.09 694.003 1771.9 702.56 1879.35 746.344C1986.98 790.199 2078.84 865.92 2150.59 957.1",
+ "M-134.896 223.127C-152.838 293.322 -97.7516 365.518 -30.339 390.517C-24.3159 392.761 -18.2135 394.679 -12.0804 396.327C50.5724 413.153 117.863 401.726 181.14 385.14C193.33 381.949 205.501 378.547 217.66 375.114C274.787 358.974 332.423 342.139 391.935 341.858C411.2 341.741 430.123 343.384 448.741 346.622C574.625 368.746 680.544 464.719 768.021 561.186C774.372 568.198 780.735 575.24 787.081 582.327C881.117 686.889 980.631 787.483 1102.18 832.678C1143.66 848.095 1185.99 863.184 1233.93 860.008C1290.91 856.311 1346.58 829.294 1395.17 800.53C1428.3 780.935 1459.66 760.091 1492.7 742.48C1508.24 734.221 1524.17 726.678 1540.8 720.185C1646.74 678.881 1775.43 686.907 1885.45 732.15C1995.62 777.476 2088.92 856.279 2161.87 950.166",
+ "M-134.603 203.437C-152.602 273.584 -98.1348 345.79 -31.1106 371.504C-25.1051 373.793 -19.0381 375.799 -12.9536 377.504C49.4213 394.963 116.678 384.393 180.061 368.567C192.273 365.513 204.467 362.248 216.647 358.952C273.842 343.479 331.536 327.205 390.999 327.238C410.243 327.24 429.147 328.927 447.731 332.254C573.557 354.842 678.999 450.983 765.672 548.053C771.961 555.091 778.245 562.204 784.529 569.318C877.486 674.526 975.321 775.733 1094.31 824.7C1136.08 841.898 1178.81 859.345 1227.95 856.857C1286.39 853.996 1343.43 825.551 1392.47 794.944C1425.91 774.084 1457.32 751.827 1490.6 732.828C1506.23 723.91 1522.32 715.744 1539.19 708.676C1646.52 663.699 1779.12 671.18 1891.69 717.926C2004.39 764.724 2099.14 846.565 2173.28 943.203",
+ "M-134.306 183.756C-152.345 253.81 -98.5322 326.114 -31.892 352.469C-25.9351 354.816 -19.9166 356.879 -13.8055 358.646C48.3357 376.755 115.527 367.055 179.017 351.989C191.22 349.085 203.436 345.957 215.639 342.798C272.887 327.961 330.696 312.297 390.067 312.626C409.275 312.717 428.145 314.492 446.724 317.893C572.493 340.946 677.458 437.256 763.296 534.941C769.536 542.037 775.758 549.176 781.949 556.33C873.829 662.184 969.976 764.154 1086.43 816.775C1128.51 835.783 1171.6 855.528 1221.95 853.727C1281.85 851.704 1340.24 821.799 1389.7 789.361C1423.45 767.268 1454.9 743.566 1488.4 723.192C1504.15 713.634 1520.35 704.84 1537.44 697.198C1646.17 648.578 1782.68 655.514 1897.8 703.763C2013.06 752.064 2109.22 836.925 2184.57 936.3",
+ "M-134.041 164.084C-152.138 234.09 -98.9741 306.417 -32.6604 333.462C-26.7389 335.897 -20.738 338.005 -14.6755 339.829C47.201 358.601 114.344 349.728 177.91 335.434C190.135 332.668 202.387 329.708 214.581 326.698C271.896 312.529 329.794 297.413 389.117 298.055C408.303 298.265 427.155 300.085 445.73 303.562C571.455 327.109 675.912 423.601 760.933 521.857C767.111 528.979 773.253 536.19 779.396 543.401C870.197 649.902 964.59 752.736 1078.56 808.877C1120.92 829.741 1164.41 851.77 1215.95 850.669C1277.29 849.453 1337.05 818.119 1386.95 783.882C1420.98 760.57 1452.49 735.409 1486.21 713.661C1502.05 703.445 1518.41 694.027 1535.73 685.81C1645.87 633.547 1786.28 639.938 1903.94 689.659C2021.74 739.433 2119.32 827.345 2195.88 929.458",
+ "M-133.759 144.37C-151.895 214.283 -99.3683 286.664 -33.443 314.426C-27.539 316.905 -21.5734 319.101 -15.5153 321C46.0966 340.435 113.205 332.42 176.878 318.886C189.139 316.287 201.368 313.446 213.585 310.574C270.967 297.071 328.923 282.516 388.197 283.472C407.348 283.771 426.208 285.697 444.735 289.231C570.403 313.243 674.383 409.903 758.568 508.774C764.698 515.954 770.778 523.192 776.828 530.442C866.565 637.621 959.15 741.452 1070.7 800.982C1113.35 823.731 1157.24 847.969 1209.96 847.569C1272.76 847.19 1333.87 814.396 1384.23 778.347C1418.58 753.801 1450.15 727.152 1484.09 704.06C1500.06 693.203 1516.55 683.144 1534.07 674.366C1645.6 618.429 1789.92 624.276 1910.13 675.5C2030.48 726.776 2129.47 817.709 2207.22 922.572",
+ "M-133.463 124.681C-151.657 194.545 -99.7797 266.949 -34.1809 295.401C-28.3256 297.937 -22.3777 300.178 -16.3548 302.166C45.0101 322.22 112.053 315.075 175.833 302.3C188.116 299.839 200.35 297.179 212.575 294.413C270.024 281.577 328.083 267.601 387.264 268.853C406.38 269.241 425.205 271.254 443.727 274.864C569.307 299.353 672.854 396.199 756.192 495.655C762.228 502.875 768.26 510.17 774.248 517.447C862.907 625.273 953.65 730.188 1062.83 793.004C1105.74 817.698 1150.06 844.13 1203.99 844.418C1268.25 844.877 1330.71 810.622 1381.5 772.744C1416.11 746.947 1447.76 718.87 1481.92 694.404C1497.99 682.919 1514.62 672.251 1532.36 662.867C1645.28 603.287 1793.51 608.589 1916.27 661.285C2039.15 714.034 2139.56 808.017 2218.52 915.618",
+ "M-133.197 105.016C-151.431 174.787 -100.221 247.258 -34.9931 276.382C-29.1863 278.976 -23.2428 281.291 -17.2685 283.337C43.8318 304.054 110.84 297.766 174.727 285.752C187.001 283.441 199.288 280.904 211.549 278.306C269.083 266.093 327.212 252.709 386.315 254.288C405.408 254.795 424.216 256.853 442.72 260.506C568.243 285.459 671.313 382.474 753.846 482.532C759.834 489.81 765.805 497.131 771.7 504.448C859.28 612.921 948.159 719.04 1054.98 785.068C1098.15 811.736 1142.87 840.302 1197.98 841.291C1263.7 842.556 1327.49 806.885 1378.74 767.195C1413.67 740.165 1445.36 710.643 1479.77 684.789C1495.91 672.646 1512.72 661.354 1530.68 651.396C1645.01 588.173 1797.14 592.899 1922.44 647.098C2047.88 701.35 2149.7 798.353 2229.87 908.692",
+ "M-132.9 85.3296C-151.192 155.053 -100.601 227.534 -35.7616 257.374C-29.9591 260.043 -24.0641 262.416 -18.1074 264.506C42.7591 285.873 109.689 280.424 173.664 269.214C185.961 267.04 198.239 264.653 210.522 262.192C268.123 250.646 326.31 237.823 385.364 239.716C404.423 240.311 423.195 242.458 441.695 246.186C567.174 271.634 669.767 368.818 751.452 469.46C757.378 476.764 763.255 484.126 769.115 491.531C855.618 600.65 942.535 708.09 1047.09 777.182C1090.46 805.852 1135.66 836.556 1191.98 838.232C1259.15 840.334 1324.29 803.204 1375.98 761.714C1411.19 733.465 1442.95 702.485 1477.57 675.256C1493.85 662.472 1510.75 650.553 1528.95 640.019C1644.66 573.123 1800.71 577.336 1928.55 633.007C2056.53 688.73 2159.77 788.785 2241.16 901.861",
+ "M-132.619 65.6142C-150.95 135.244 -101.014 207.824 -36.5137 238.322C-30.7599 241.049 -24.9134 243.479 -18.9611 245.645C41.6408 267.675 108.522 263.052 172.605 252.602C184.937 250.596 197.238 248.346 209.512 246.035C267.18 235.157 325.469 222.912 384.431 225.101C403.467 225.816 422.222 228.006 440.686 231.823C566.109 257.735 668.223 355.087 749.074 456.345C754.951 463.707 760.767 471.095 766.534 478.54C851.958 588.306 936.883 697.078 1039.2 769.254C1082.76 799.969 1128.47 832.722 1185.98 835.099C1254.61 838.039 1321.1 799.448 1373.26 756.147C1408.78 726.663 1440.57 694.208 1475.42 665.636C1491.77 652.193 1508.85 639.651 1527.24 628.556C1644.36 558.017 1804.3 561.654 1934.7 618.828C2065.23 676.054 2169.88 779.129 2252.48 894.943",
+ "M-132.324 45.9289C-150.682 115.497 -101.427 188.113 -37.2975 219.284C-31.5612 222.055 -25.75 224.574 -19.8154 226.783C40.5086 249.445 107.369 245.711 171.558 236.02C183.912 234.151 196.205 232.052 208.501 229.878C266.236 219.666 324.614 207.969 383.496 210.486C402.497 211.289 421.248 213.554 439.708 217.447C565.073 243.822 666.711 341.343 746.726 443.217C752.542 450.605 758.278 458.063 763.983 465.535C848.33 575.948 931.151 686.137 1031.34 761.281C1075.06 794.085 1121.29 828.888 1179.96 831.935C1250.04 835.681 1317.9 795.661 1370.48 750.53C1406.28 719.827 1438.13 685.913 1473.23 655.953C1489.72 641.87 1506.92 628.687 1525.54 617.017C1644.05 542.804 1807.91 545.927 1940.85 604.573C2073.91 663.271 2179.98 769.397 2263.77 887.962",
+ "M-132.058 26.2597C-150.486 95.7487 -101.836 168.405 -38.0645 200.279C-32.3635 203.138 -26.5701 205.701 -20.684 207.968C39.4063 231.28 106.188 228.386 170.484 219.455C182.829 217.736 195.188 215.791 207.463 213.736C265.264 204.192 323.701 193.056 382.565 195.873C401.531 196.765 420.26 199.15 438.702 203.086C563.993 229.97 665.184 327.646 744.351 430.104C750.118 437.55 755.792 445.035 761.405 452.547C844.673 563.606 925.387 675.288 1023.46 753.355C1067.32 788.262 1114.08 825.07 1173.97 828.836C1245.51 833.419 1314.74 791.97 1367.74 745.009C1403.84 713.042 1435.78 677.701 1471.04 646.349C1487.63 631.638 1504.96 617.814 1523.81 605.569C1643.75 527.7 1811.47 530.261 1946.97 590.441C2082.58 650.611 2190.08 759.788 2275.07 881.091",
+ "M-131.761 6.57552C-150.217 76.0027 -102.247 148.695 -38.833 181.272C-33.1807 184.189 -27.4048 186.796 -21.554 189.152C38.2716 213.127 105.019 211.09 169.421 202.919C181.789 201.336 194.139 199.542 206.48 197.642C264.335 188.734 322.887 178.207 381.673 181.351C400.616 182.362 419.327 184.791 437.721 188.785C562.955 216.133 663.638 313.991 742.032 417.038C747.706 424.523 753.363 432.053 758.926 439.622C841.117 551.328 919.617 664.51 1015.67 745.461C1059.6 782.499 1106.97 821.316 1168.06 825.738C1241.06 831.159 1311.63 788.25 1365.07 739.489C1401.49 706.289 1433.46 669.503 1468.94 636.777C1485.64 621.394 1503.11 606.96 1522.19 594.141C1643.54 512.629 1815.17 514.645 1953.21 576.297C2091.37 637.97 2200.3 750.154 2286.48 874.208",
+ "M-131.479 -13.1409C-150.006 56.2069 -102.673 128.953 -39.6158 162.234C-33.9811 165.195 -28.2406 167.89 -22.4074 170.29C37.1712 194.884 103.853 193.717 168.345 186.35C180.748 184.936 193.107 183.248 205.439 181.498C263.361 173.257 322.002 163.278 380.708 166.749C399.617 167.848 418.292 170.366 436.682 174.435C561.858 202.247 662.077 300.304 739.623 403.936C745.249 411.479 750.812 419.048 756.314 426.644C837.396 539.01 913.652 653.707 1007.74 737.515C1051.74 776.682 1099.74 817.464 1162 822.631C1236.44 828.858 1308.38 784.52 1362.27 733.917C1398.97 699.497 1431.01 661.253 1466.74 627.139C1483.54 611.128 1501.16 596.04 1520.44 582.66C1643.18 497.474 1818.72 498.945 1959.31 562.1C2100.01 625.246 2210.37 740.511 2297.76 867.272",
+ "M-131.183 -32.8251C-149.736 36.4608 -103.04 109.261 -40.367 143.183C-34.7809 146.201 -29.0446 148.972 -23.2601 151.429C36.0539 176.686 102.701 176.377 167.286 169.739C179.712 168.461 192.075 166.954 204.43 165.341C262.45 157.754 321.117 148.349 379.775 152.134C398.662 153.353 417.32 155.915 435.705 160.059C560.838 188.366 660.566 286.561 737.277 390.808C742.841 398.377 748.356 406.004 753.765 413.64C833.782 526.683 907.701 642.934 999.895 729.573C1043.92 770.927 1092.57 813.661 1156.02 819.485C1231.93 826.55 1305.22 780.751 1359.55 728.349C1396.56 692.696 1428.63 652.976 1464.59 617.518C1481.47 600.88 1499.23 585.151 1518.74 571.196C1642.88 482.368 1822.29 483.307 1965.45 547.921C2108.71 612.569 2220.48 730.855 2309.08 860.353",
+ "M-130.918 -52.4957C-149.541 16.7107 -103.481 89.5652 -41.166 124.19C-35.5842 127.283 -29.9098 130.081 -24.1606 132.626C34.8888 158.546 101.488 159.063 166.193 153.216C178.61 152.089 191.027 150.705 203.373 149.242C261.459 142.322 320.216 133.466 378.795 137.578C397.646 138.884 416.299 141.521 434.649 145.754C559.725 174.525 658.99 272.92 734.852 377.751C740.367 385.378 745.79 393.045 751.137 400.707C830.076 514.397 901.565 632.242 991.953 721.672C1035.96 765.195 1085.29 809.868 1149.97 816.41C1227.37 824.299 1301.98 777.054 1356.74 722.853C1394.02 685.948 1426.18 644.801 1462.38 607.956C1479.38 590.646 1497.28 574.307 1517.02 559.777C1642.56 467.306 1825.87 467.67 1971.58 533.786C2117.37 599.907 2230.57 721.244 2320.35 853.493",
+ "M-130.622 -72.1836C-149.272 -3.03889 -103.893 69.8518 -41.9042 105.166C-36.371 108.317 -30.7319 111.203 -24.9693 113.779C33.8464 140.35 100.38 141.737 165.179 136.619C177.618 135.628 190.039 134.426 202.394 133.069C260.534 126.785 319.407 118.538 377.893 122.946C396.722 124.372 415.327 127.067 433.672 131.375C558.66 160.623 657.478 259.173 732.506 364.619C737.959 372.273 743.333 379.997 748.601 387.731C826.461 502.067 895.507 621.476 984.117 713.758C1028.05 759.508 1078.14 806.094 1143.99 813.305C1222.82 822.001 1298.8 773.327 1354.03 717.313C1391.62 679.176 1423.82 636.584 1460.24 598.364C1477.34 580.427 1495.38 563.478 1515.33 548.342C1642.26 452.197 1829.49 452.047 1977.74 519.636C2126.05 587.272 2240.69 711.616 2331.68 846.603",
+ "M-130.339 -91.8958C-149.06 -22.8305 -104.286 50.1008 -42.6992 86.1005C-37.2145 89.3091 -31.5798 92.27 -25.8658 94.9039C32.6719 122.107 99.1708 124.351 164.059 120.037C176.52 119.183 188.964 118.118 201.354 116.929C259.561 111.312 318.492 103.626 376.929 108.348C395.723 109.863 414.324 112.632 432.665 117.015C557.609 146.758 655.937 245.446 730.129 351.508C735.534 359.219 740.815 366.983 746.021 374.743C822.803 489.726 889.313 610.738 976.254 705.788C1020.11 753.735 1070.99 802.25 1138.02 810.162C1218.31 819.695 1295.64 769.561 1351.3 711.717C1389.17 672.36 1421.43 628.31 1458.07 588.716C1475.28 570.107 1493.46 552.548 1513.64 536.838C1641.98 437.05 1833.1 436.324 1983.9 505.416C2134.75 574.525 2250.81 701.919 2343.02 839.644",
+ "M-130.042 -111.579C-148.79 -42.5757 -104.697 30.3919 -43.4367 67.0813C-37.9564 70.3651 -32.3835 73.3526 -26.6606 76.0925C31.6434 103.945 98.0768 107.06 163.072 103.505C175.538 102.833 187.99 101.874 200.402 100.822C258.677 95.8719 317.696 88.7338 376.085 93.7694C394.844 95.3724 413.422 98.2614 431.733 102.657C556.62 132.865 654.483 231.752 727.859 338.385C733.201 346.123 738.421 353.913 743.547 361.744C819.251 477.374 883.181 599.972 968.48 697.852C1012.2 748.052 1063.88 798.422 1132.12 807.022C1213.88 817.392 1292.56 765.797 1348.65 706.155C1386.83 665.565 1419.15 620.025 1456.02 579.088C1473.33 559.851 1491.67 541.638 1512.05 525.366C1641.77 421.905 1836.81 420.665 1990.2 491.246C2143.59 561.827 2261.07 692.273 2354.49 832.735",
+ "M-129.779 -131.252C-148.597 -62.3275 -105.097 10.7117 -44.2378 48.0866C-38.8061 51.4278 -33.2376 54.4906 -27.5632 57.288C30.4762 85.8036 96.8616 89.745 161.963 86.9501C174.451 86.4149 186.939 85.6235 199.33 84.6908C257.671 80.408 316.792 73.8486 375.089 79.1804C393.826 80.9027 412.387 83.8358 430.662 88.3203C555.492 118.992 652.878 218.047 725.418 325.296C730.682 333.104 735.839 340.922 740.917 348.81C815.543 465.087 876.848 589.252 960.536 689.949C1004.11 742.372 1056.61 794.658 1126.04 803.959C1209.24 815.135 1289.29 762.112 1345.81 700.671C1384.28 658.86 1416.67 611.863 1453.75 569.551C1471.15 549.687 1489.62 530.833 1510.23 513.986C1641.36 406.882 1840.31 405.098 1996.23 477.151C2152.17 549.235 2271.06 682.701 2365.7 825.9",
+ "M-129.482 -150.938C-148.327 -82.0763 -105.508 -9.00068 -45.0062 29.0772C-39.5922 32.4627 -34.059 35.6136 -28.4332 38.4685C29.3591 67.6031 95.6791 72.415 160.901 70.411C173.411 70.0127 185.89 69.3715 198.316 68.6066C256.724 64.991 315.904 58.9926 374.152 64.6381C392.854 66.4489 411.41 69.4572 429.681 74.0169C554.454 105.152 651.345 204.421 723.068 312.24C728.27 320.075 733.378 327.95 738.363 335.879C811.912 452.802 870.517 578.531 952.682 682.08C996.055 736.752 1049.46 790.884 1120.06 800.886C1204.73 812.899 1286.14 758.447 1343.1 695.132C1381.87 652.057 1414.31 603.646 1451.63 559.946C1469.16 539.41 1487.76 519.946 1508.6 502.525C1641.13 391.778 1843.97 389.418 2002.45 462.974C2160.93 536.53 2281.24 673.047 2377.09 818.984",
+ "M-129.2 -170.657C-148.116 -101.874 -105.933 -28.7449 -45.7713 9.99186C-40.4058 13.4348 -34.8902 16.6302 -29.2688 19.5603C28.259 49.358 94.5443 55.0271 159.86 53.7519C172.392 53.4905 184.907 53.0172 197.311 52.3716C255.804 49.3788 315.054 43.9724 373.223 49.945C391.903 51.8751 410.411 54.941 428.677 59.5757C553.375 91.2193 649.807 190.612 720.695 299.047C725.848 306.94 730.864 314.854 735.787 322.809C808.257 440.379 864.119 567.654 944.792 674.042C987.96 730.964 1042.25 786.985 1114.06 797.674C1200.19 810.525 1282.95 754.613 1340.35 689.499C1379.43 645.191 1411.91 595.335 1449.45 550.26C1467.07 529.097 1485.83 508.979 1506.87 490.996C1640.79 376.575 1847.55 373.701 2008.57 448.73C2169.6 523.788 2291.32 663.326 2388.35 812.014",
+ "M-128.936 -190.323C-147.878 -121.602 -106.345 -48.4495 -46.5712 -8.99638C-41.241 -5.46501 -35.7431 -2.22561 -30.1703 0.761936C27.0928 31.2228 93.3303 37.7183 158.735 37.2472C171.272 37.167 183.796 36.7997 196.266 36.3087C254.826 33.983 314.178 29.1552 372.255 35.424C390.899 37.4425 409.403 40.5835 427.634 45.3067C552.275 77.4143 648.243 177.007 718.282 286.026C723.374 293.946 728.341 301.918 733.171 309.913C804.563 428.129 857.637 556.933 936.876 666.208C979.763 725.375 1035 783.259 1108 794.649C1195.57 808.307 1279.69 750.965 1337.53 684.052C1376.89 638.524 1409.44 587.21 1447.18 540.73C1464.93 518.926 1483.79 498.18 1505.06 479.623C1640.38 361.559 1851.04 358.11 2014.61 434.641C2178.18 511.172 2301.32 653.76 2399.56 805.186",
+ "M-128.638 -210.011C-147.62 -141.382 -106.754 -68.1626 -47.3073 -28.0197C-41.9947 -24.4441 -36.563 -21.1029 -30.9769 -18.0844C26.0525 13.0263 92.2246 20.3924 157.723 20.6501C170.282 20.7069 182.828 20.4763 195.289 20.1355C253.916 18.4769 313.327 14.2103 371.355 20.7929C389.995 22.8865 408.432 26.1292 426.677 30.8832C551.261 63.4549 646.751 163.216 715.987 272.837C721.029 280.814 725.904 288.826 730.686 296.879C801.013 415.773 851.272 546.043 929.077 658.206C971.683 719.617 1027.88 779.396 1102.09 791.473C1191.12 805.968 1276.6 747.166 1334.87 678.454C1374.54 631.693 1407.12 578.903 1445.12 531.067C1462.95 508.604 1481.98 487.235 1503.48 468.103C1640.2 346.396 1854.77 342.402 2020.88 420.405C2187 498.439 2311.58 644.034 2411.01 798.211",
+ "M-128.342 -229.697C-149.078 -155.004 -99.5103 -74.7583 -31.8474 -36.9029C35.8023 0.921561 116.728 5.34993 194.262 4.02153C271.796 2.69313 350.763 -3.31659 425.682 16.5496C559.238 52.0022 658.882 164.407 728.087 283.93C797.337 403.471 844.719 535.235 921.165 650.289C963.459 713.959 1020.67 775.574 1096.06 788.352C1186.55 803.684 1273.38 743.423 1332.1 672.867C1390.83 602.312 1433.78 518.326 1501.73 456.62C1639.84 331.24 1858.32 326.701 2026.98 406.207C2195.64 485.713 2321.64 634.359 2422.28 791.274",
+];
+
+const max = paths.length - 1;
+
+gsap.registerPlugin(MotionPathPlugin);
+
+function getRandomNumber(excludedNumbers: number[]): number {
+ const possibleNumbers = Array.from({ length: 15 }, (_, i) => i).filter((num) => !excludedNumbers.includes(num));
+ if (possibleNumbers.length === 0) {
+ return 0;
+ }
+ const randomIndex = Math.floor(Math.random() * possibleNumbers.length);
+ return possibleNumbers[randomIndex];
+}
+
+const generateAnimationData = () => {
+ const availableIndexes = [...Array(max).keys()];
+
+ const previousDelays: Array<{ pathIndex: number; delay: number }> = [];
+
+ return tools.map((tool, index) => {
+ const itemIndex = availableIndexes[Math.floor(Math.random() * availableIndexes.length)];
+ availableIndexes.splice(itemIndex, 1); // prevent duplicates
+
+ // Index should be max and it has to start counting from 1 over again
+ const pathIndex = itemIndex - Math.floor(itemIndex / max) * max + 1;
+ const duration = 16;
+
+ const neighbors = previousDelays.filter((d) => d.pathIndex === pathIndex - 1 || d.pathIndex === pathIndex + 1);
+
+ // Cannot be in the offset range of neighbors delays
+ // To prevent overlapping of the dots
+ const delay = getRandomNumber(
+ neighbors
+ .map((d) => d.delay)
+ .reduce((acc, curr) => {
+ const numbers = [curr - 2, curr - 1, curr, curr + 1, curr + 2].filter((n) => n >= 0);
+
+ return [...new Set([...acc, ...numbers])];
+ }, [] as number[]),
+ );
+
+ previousDelays.push({ pathIndex, delay });
+
+ const timeline = gsap.timeline({
+ repeat: -1,
+ delay,
+ repeatRefresh: true,
+ });
+
+ const path = `#path${pathIndex}`;
+ const item = `#idItem${index}`;
+ const dot = `#idDot${index}`;
+ const glow = `#idGlow${pathIndex}`;
+ const label = `#idLabel${index}`;
+
+ const props: Parameters[0] = {
+ // IDS
+ path,
+ item,
+ dot,
+ glow,
+ label,
+ // Settings
+ timeline,
+ delay,
+ duration,
+ // Other
+ pathIndex,
+ index,
+ };
+
+ return {
+ ...tool,
+ props,
+ };
+ });
+};
+
+export const Paths = () => {
+ const isMounted = useIsMounted();
+ const [data, setData] = useState>([]);
+ const [width, height] = useWindowSize();
+
+ const handleGenerateData = useCallback(() => {
+ if (data?.length) return;
+ const response = generateAnimationData();
+ setData(response);
+ return response;
+ }, [data]);
+
+ useLayoutEffect(() => {
+ handleGenerateData();
+ return () => {
+ data.forEach((tool) => {
+ tool.props.timeline.clear();
+ });
+ };
+ }, [data, width, height, isMounted, handleGenerateData]);
+
+ if (width < 768) {
+ return null;
+ }
+
+ return (
+ <>
+ {data.map((tool) => (
+
+ ))}
+
+
+
+ {paths.map((path, i) => (
+
+ ))}
+
+ {data.map((tool) => (
+
+ ))}
+
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+};
diff --git a/documentation/src/components/landing/index.ts b/documentation/src/components/landing/index.ts
new file mode 100644
index 000000000..30ab41b99
--- /dev/null
+++ b/documentation/src/components/landing/index.ts
@@ -0,0 +1 @@
+export * from "./landing";
diff --git a/documentation/src/components/landing/integrations/integrations.tsx b/documentation/src/components/landing/integrations/integrations.tsx
new file mode 100644
index 000000000..fed79d4cc
--- /dev/null
+++ b/documentation/src/components/landing/integrations/integrations.tsx
@@ -0,0 +1,136 @@
+import { Theatre } from "@react-theater/scroll";
+import { Description, FadeIn, Particles, ScaleOut, Title } from "@site/src/components";
+import ReactIcon from "@site/static/img/integration-react.svg";
+import NextIcon from "@site/static/img/integration-next.svg";
+import RemixIcon from "@site/static/img/integration-remix.svg";
+import AstroIcon from "@site/static/img/integration-astro.svg";
+import NestIcon from "@site/static/img/integration-nest.svg";
+import GraphqlIcon from "@site/static/img/integration-graphql.svg";
+import RestIcon from "@site/static/img/integration-rest.svg";
+import StrapiIcon from "@site/static/img/integration-strapi.svg";
+import HasuraIcon from "@site/static/img/integration-hasura.svg";
+import AppwriteIcon from "@site/static/img/integration-appwrite.svg";
+import AirtableIcon from "@site/static/img/integration-airtable.svg";
+import MedusaIcon from "@site/static/img/integration-medusa.svg";
+import FirebaseIcon from "@site/static/img/integration-firebase.svg";
+import SocketsIcon from "@site/static/img/integration-sockets.svg";
+import KindeIcon from "@site/static/img/integration-kinde.svg";
+import ClerkIcon from "@site/static/img/integration-clerk.svg";
+import MapboxIcon from "@site/static/img/integration-mapbox.svg";
+import GoogleMapsIcon from "@site/static/img/integration-google-maps.svg";
+import Auth0Icon from "@site/static/img/integration-auth0.svg";
+
+/* eslint-disable react/no-array-index-key */
+// 8
+const integrationsInner = [
+ ReactIcon,
+ FirebaseIcon,
+ StrapiIcon,
+ MedusaIcon,
+ NestIcon,
+ KindeIcon,
+ GraphqlIcon,
+ Auth0Icon,
+];
+// 12
+const integrationsOuter = [
+ AstroIcon,
+ SocketsIcon,
+ AirtableIcon,
+ RestIcon,
+ MapboxIcon,
+ AppwriteIcon,
+ NextIcon,
+ Auth0Icon,
+ HasuraIcon,
+ GoogleMapsIcon,
+ RemixIcon,
+ ClerkIcon,
+];
+
+export const Integrations = () => {
+ return (
+
+
+
+
+
+
+ Integrates with the tools of your choice
+
+
+
+
+
+ Written with no additional dependencies, fits perfectly into cutting edge solutions
+
+
+
+
+
+ {/* Circle Inner */}
+
+
+ {integrationsInner.map((Icon, i) => (
+
+ ))}
+
+
+
+
+ {/* Circle Outer */}
+
+
+ {integrationsOuter.map((Icon, i) => (
+
+ ))}
+
+
+
+
+ {/* Backdrop */}
+
+
+ );
+};
diff --git a/documentation/src/components/landing/landing.tsx b/documentation/src/components/landing/landing.tsx
new file mode 100644
index 000000000..55d5c27a2
--- /dev/null
+++ b/documentation/src/components/landing/landing.tsx
@@ -0,0 +1,54 @@
+import { useState } from "react";
+import { useDidMount, useWindowEvent } from "@reins/hooks";
+import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
+import Layout from "@theme/Layout";
+
+import { Hero } from "./hero";
+import { Clients } from "./clients";
+import { Blocks } from "./blocks";
+import { CallToAction } from "./call-to-action";
+import { Modules } from "./modules/modules";
+// import { Integrations } from "./integrations/integrations";
+import { Features } from "./features/features";
+import { Example } from "./example/example";
+import { Preview } from "./preview/preview";
+import { Sponsors } from "./sponsors/sponsors";
+
+export const Landing = () => {
+ const { siteConfig } = useDocusaurusContext();
+
+ const [hide, setHide] = useState(false);
+
+ useDidMount(() => {
+ window.scrollTo(0, 0);
+ });
+
+ useWindowEvent(
+ "scroll",
+ () => {
+ const hideValue = window.scrollY > window.innerHeight * 2;
+
+ if (hide !== hideValue) {
+ setHide(hideValue);
+ }
+ },
+ [hide],
+ );
+
+ return (
+
+
+
+
+
+
+
+ {/*
*/}
+
+
+
+
+
+
+ );
+};
diff --git a/documentation/src/components/landing/modules/cards.tsx b/documentation/src/components/landing/modules/cards.tsx
new file mode 100644
index 000000000..cfdd78723
--- /dev/null
+++ b/documentation/src/components/landing/modules/cards.tsx
@@ -0,0 +1,52 @@
+/* eslint-disable react/no-array-index-key */
+import { useSidebar } from "@site/src/hooks/use-sidebar";
+import { Description, FadeIn, Title } from "@site/src/components";
+import { useWindowSize } from "@reins/hooks";
+import { Theatre } from "@react-theater/scroll";
+import { getAnimationValue } from "@site/src/utils/animation";
+
+export const Cards = () => {
+ const [width] = useWindowSize();
+ const { sidebar } = useSidebar({ showAllPackages: true });
+ // eslint-disable-next-line no-nested-ternary
+ const columns = width < 640 ? 1 : width < 767 ? 2 : 3;
+
+ return (
+
+
+
+ );
+};
diff --git a/documentation/src/components/landing/modules/modules.tsx b/documentation/src/components/landing/modules/modules.tsx
new file mode 100644
index 000000000..5ec303cf4
--- /dev/null
+++ b/documentation/src/components/landing/modules/modules.tsx
@@ -0,0 +1,42 @@
+/* eslint-disable react/no-array-index-key */
+/* eslint-disable no-nested-ternary */
+import { FadeIn } from "@site/src/components/fade-in/fade-in";
+import { Title } from "@site/src/components";
+
+import { Cards } from "./cards";
+
+export const Modules = () => {
+ return (
+
+
+
+ {/* Section header */}
+
+
+
+
+ Where DX meets business
+
+
+
+
+
+ Scale your development
+
+
+
+
+ With our platform you can build any type of application, from simple landing pages to complex enterprise
+ systems.
+
+
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/documentation/src/components/landing/preview/border-beam.tsx b/documentation/src/components/landing/preview/border-beam.tsx
new file mode 100644
index 000000000..b29bb5e26
--- /dev/null
+++ b/documentation/src/components/landing/preview/border-beam.tsx
@@ -0,0 +1,95 @@
+"use client";
+
+import { motion, MotionStyle, Transition } from "motion/react";
+
+import { cn } from "../../../lib/utils";
+
+interface BorderBeamProps {
+ /**
+ * The size of the border beam.
+ */
+ size?: number;
+ /**
+ * The duration of the border beam.
+ */
+ duration?: number;
+ /**
+ * The delay of the border beam.
+ */
+ delay?: number;
+ /**
+ * The color of the border beam from.
+ */
+ colorFrom?: string;
+ /**
+ * The color of the border beam to.
+ */
+ colorTo?: string;
+ /**
+ * The motion transition of the border beam.
+ */
+ transition?: Transition;
+ /**
+ * The class name of the border beam.
+ */
+ className?: string;
+ /**
+ * The style of the border beam.
+ */
+ style?: React.CSSProperties;
+ /**
+ * Whether to reverse the animation direction.
+ */
+ reverse?: boolean;
+ /**
+ * The initial offset position (0-100).
+ */
+ initialOffset?: number;
+}
+
+export const BorderBeam = ({
+ className,
+ size = 50,
+ delay = 0,
+ duration = 6,
+ colorFrom = "#ffaa40",
+ colorTo = "#9c40ff",
+ transition,
+ style,
+ reverse = false,
+ initialOffset = 0,
+}: BorderBeamProps) => {
+ return (
+
+
+
+ );
+};
diff --git a/documentation/src/components/landing/preview/preview.tsx b/documentation/src/components/landing/preview/preview.tsx
new file mode 100644
index 000000000..ecc0138cc
--- /dev/null
+++ b/documentation/src/components/landing/preview/preview.tsx
@@ -0,0 +1,176 @@
+import React, { useState, useEffect } from "react";
+import DashboardPreview from "@site/static/img/previews/app.png";
+import ProjectPerformance from "@site/static/img/previews/project-performance.png";
+import ProjectCache from "@site/static/img/previews/project-cache.png";
+import NetworkDetails from "@site/static/img/previews/network-details.png";
+import CacheDetails from "@site/static/img/previews/cache-details.png";
+import { Title } from "@site/src/components";
+import { FadeIn } from "@site/src/components/fade-in/fade-in";
+import Link from "@docusaurus/Link";
+import { ChevronLeft, ChevronRight } from "lucide-react";
+
+import { BorderBeam } from "./border-beam";
+
+const sections = [
+ {
+ title: "Dedicated Devtools",
+ description:
+ "Seamlessly integrate your app with Hyper Flow to unlock real-time request monitoring and gain instant insights.",
+ image: DashboardPreview,
+ },
+ {
+ title: "Performance Analysis",
+ description: "Dive deep into your project's performance metrics, identify bottlenecks, and optimize efficiently.",
+ image: ProjectPerformance,
+ },
+ {
+ title: "Cache Management",
+ description:
+ "Visualize and manage your application's cache, ensuring optimal data retrieval and storage strategies.",
+ image: ProjectCache,
+ },
+ {
+ title: "Network Inspector",
+ description:
+ "Inspect every network request in detail, analyze headers, payloads, and timings to debug connectivity issues.",
+ image: NetworkDetails,
+ },
+ {
+ title: "Cache Viewer",
+ description:
+ "Explore cached data entries, understand expiration times, and fine-tune your caching mechanisms for peak performance.",
+ image: CacheDetails,
+ },
+];
+
+const SLIDE_DURATION = 4000;
+
+export function Preview(): JSX.Element {
+ const [currentSlide, setCurrentSlide] = useState(0);
+ const [, setTimeLeft] = useState(SLIDE_DURATION);
+ const intervalRef = React.useRef(null);
+
+ const startTimer = () => {
+ if (intervalRef.current) clearInterval(intervalRef.current);
+ setTimeLeft(SLIDE_DURATION);
+ intervalRef.current = setInterval(() => {
+ setTimeLeft((prev) => {
+ if (prev <= 1000) {
+ // Check if it's time to switch *before* decrementing to 0
+ setCurrentSlide((prevSlide) => (prevSlide + 1) % sections.length);
+ return SLIDE_DURATION; // Reset timer for the new slide
+ }
+ return prev - 1000;
+ });
+ }, 1000);
+ };
+
+ useEffect(() => {
+ startTimer();
+ return () => {
+ if (intervalRef.current) clearInterval(intervalRef.current);
+ }; // Clear interval on component unmount
+ }, []);
+
+ const goToNext = () => {
+ setCurrentSlide((prevSlide) => (prevSlide + 1) % sections.length);
+ startTimer(); // Reset and restart timer
+ };
+
+ const goToPrevious = () => {
+ setCurrentSlide((prevSlide) => (prevSlide - 1 + sections.length) % sections.length);
+ startTimer(); // Reset and restart timer
+ };
+
+ const currentSection = sections[currentSlide];
+
+ return (
+
+ {/* */}
+
+ {/* Section header */}
+
+
+
+
+ Power up your development workflow
+
+
+
+
+
+ Hyper Flow
+
+
+
+
+ Experience next-level debugging with real-time request tracking, detailed error analysis, and comprehensive
+ performance metrics.
+
+
+
+
+
+ Download Hyper Flow
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* bottom gradient */}
+
+
+ {/* Previous Button - Positioned absolutely */}
+
+
+
+
+ {/* Next Button - Positioned absolutely */}
+
+
+
+
+
+
+
+
+ {/* Bottom section with active slide info (no buttons) */}
+
+ {/*
+
+
+
{currentSection.title}
+
{currentSection.description}
+
*/}
+
+
+ );
+}
diff --git a/documentation/src/components/landing/sponsors/sponsors.tsx b/documentation/src/components/landing/sponsors/sponsors.tsx
new file mode 100644
index 000000000..84f1d295f
--- /dev/null
+++ b/documentation/src/components/landing/sponsors/sponsors.tsx
@@ -0,0 +1,43 @@
+import { Description, FadeIn, Title } from "@site/src/components";
+
+export const Sponsors = () => {
+ return (
+
+
+
+
+
+ Support the development.
+
+
+
+
+
+ Our wonderful sponsors
+
+
+
+
+ We're grateful to the following companies and individuals who have supported us financially. You can
+ still help us by joining the{" "}
+
+ GitHub Sponsors program
+
+ .
+
+
+
+
+
+
+
+ );
+};
diff --git a/documentation/src/components/link-card/icons.tsx b/documentation/src/components/link-card/icons.tsx
new file mode 100644
index 000000000..19a73a548
--- /dev/null
+++ b/documentation/src/components/link-card/icons.tsx
@@ -0,0 +1,53 @@
+import * as React from "react";
+
+export const DocsIcon = (props: React.SVGProps) => (
+
+
+
+
+
+
+);
+
+export const IntegrationsIcon = (props: React.SVGProps) => (
+
+
+
+
+
+
+);
+
+export const GuidesIcon = (props: React.SVGProps) => (
+
+
+
+
+
+
+);
+
+export const PromoIcon = (props: React.SVGProps) => (
+
+
+
+
+
+
+);
+
+export const ExternalLinkIcon = (props: React.SVGProps) => (
+
+
+
+
+);
+
+export const ApiIcon = (props: React.SVGProps) => (
+
+
+
+
+
+
+);
diff --git a/documentation/src/components/link-card/link-card.tsx b/documentation/src/components/link-card/link-card.tsx
new file mode 100644
index 000000000..856c0f9f3
--- /dev/null
+++ b/documentation/src/components/link-card/link-card.tsx
@@ -0,0 +1,76 @@
+import Link from "@docusaurus/Link";
+import { ComponentProps } from "react";
+import { cva, type VariantProps } from "class-variance-authority";
+
+import { GuidesIcon, DocsIcon, PromoIcon, ExternalLinkIcon, ApiIcon, IntegrationsIcon } from "./icons";
+import { Noise } from "../ui/noise";
+
+const linkCardVariants = cva(
+ [
+ "px-4 py-6 my-4 !no-underline overflow-hidden",
+ "relative flex flex-col gap-2 rounded-xl transition-all duration-200 border cursor-pointer focus:outline-none",
+ "hover:ring-2 focus:ring-2",
+ "transform-gpu will-change-transform",
+ ].join(" "),
+ {
+ variants: {
+ type: {
+ docs: ["bg-gradient-to-br from-zinc-950 to-zinc-900 border-zinc-700 ring-zinc-700"].join(" "),
+ integrations: ["bg-green-900 border-green-500/30 ring-green-400"].join(" "),
+ guides: ["bg-gradient-to-br from-zinc-900 to-zinc-800 border-zinc-700 ring-zinc-700"].join(" "),
+ promo: ["bg-blue-900 border-blue-500/30 ring-blue-400"].join(),
+ external: ["bg-pink-900 border-pink-500/30 ring-pink-400"].join(" "),
+ api: ["bg-orange-900 border-orange-500/30 ring-orange-400"].join(" "),
+ },
+ },
+ defaultVariants: {
+ type: "docs",
+ },
+ },
+);
+
+type CardType = "guides" | "docs" | "promo" | "external" | "api" | "integrations";
+
+interface LinkCardProps extends ComponentProps, VariantProps {
+ title: string;
+ description?: string;
+ type?: CardType;
+}
+
+const iconMap: Record>> = {
+ guides: GuidesIcon,
+ docs: DocsIcon,
+ promo: PromoIcon,
+ external: ExternalLinkIcon,
+ api: ApiIcon,
+ integrations: IntegrationsIcon,
+};
+
+const typesNoiseOpacity = {
+ guides: "!opacity-[0.02]",
+ docs: "!opacity-[0.03]",
+ promo: "!opacity-[0.05]",
+ external: "!opacity-[0.05]",
+ api: "!opacity-[0.05]",
+ integrations: "!opacity-[0.05]",
+};
+
+export const LinkCard = ({ title, description, type = "docs", className, ...props }: LinkCardProps) => {
+ const Icon = iconMap[type];
+
+ return (
+
+
+
+
+
+
+
+
+
{title}
+ {description &&
{description}
}
+
+
+
+ );
+};
diff --git a/documentation/src/components/nav-tabs/nav-tabs.tsx b/documentation/src/components/nav-tabs/nav-tabs.tsx
new file mode 100644
index 000000000..8637d8fd0
--- /dev/null
+++ b/documentation/src/components/nav-tabs/nav-tabs.tsx
@@ -0,0 +1,43 @@
+/* eslint-disable react/no-array-index-key */
+import Link from "@docusaurus/Link";
+import { modules } from "@site/src/modules";
+import clsx from "clsx";
+
+export const NavTabs = ({
+ title,
+ tabs,
+}: {
+ title: string;
+ tabs: Array<{ to: string; label: string; active: boolean }>;
+}) => {
+ if (modules.some((section) => section.names.includes(title.toLocaleLowerCase())) || !tabs.length || tabs.length < 2) {
+ return null;
+ }
+
+ return (
+
+
+
+
+ {tabs.map((tab, idx) => (
+
+
+ {tab.label || "Usage"}
+
+
+ ))}
+
+
+
+ );
+};
diff --git a/documentation/src/components/npm-install/npm-install.tsx b/documentation/src/components/npm-install/npm-install.tsx
new file mode 100644
index 000000000..969b2992b
--- /dev/null
+++ b/documentation/src/components/npm-install/npm-install.tsx
@@ -0,0 +1,51 @@
+import { useState } from "react";
+import { useClipboard, useIsMounted } from "@reins/hooks";
+import { Copy } from "lucide-react";
+
+export const NpmInstall = ({ pkg }: { pkg: string }) => {
+ const isMounted = useIsMounted();
+ const [done, setDone] = useState(false);
+
+ const { copy } = useClipboard({
+ onSuccess: () => {
+ setDone(true);
+ setTimeout(() => {
+ if (isMounted) {
+ setDone(false);
+ }
+ }, 1000);
+ },
+ onError: () => {},
+ });
+
+ return (
+
+
copy(`npm i ${pkg}`)}
+ className="group btn-sm inline-flex items-center !px-5 !py-3 w-fit shiny-btn"
+ >
+
+ npm i{pkg} {" "}
+
+
+
+
copy(`yarn add ${pkg}`)}
+ className="group btn-sm inline-flex items-center !px-5 !py-3 w-fit shiny-btn ml-2"
+ >
+
+ yarn add
+ {pkg} {" "}
+
+
+
+ {done && (
+
+ Copied to clipboard!
+
+ )}
+
+ );
+};
diff --git a/documentation/src/components/package-details/package-details.tsx b/documentation/src/components/package-details/package-details.tsx
new file mode 100644
index 000000000..398f19e38
--- /dev/null
+++ b/documentation/src/components/package-details/package-details.tsx
@@ -0,0 +1,37 @@
+export const PackageDetails = ({
+ icon: Icon,
+ name,
+ pkg,
+}: {
+ icon: React.ComponentType>;
+ name?: string;
+ pkg: string;
+}) => {
+ const packageName = name || pkg.split("/")[1];
+
+ return (
+
+ );
+};
diff --git a/documentation/src/components/particles/index.ts b/documentation/src/components/particles/index.ts
new file mode 100644
index 000000000..134492c69
--- /dev/null
+++ b/documentation/src/components/particles/index.ts
@@ -0,0 +1 @@
+export * from "./particles";
diff --git a/documentation/src/components/particles/particles.tsx b/documentation/src/components/particles/particles.tsx
new file mode 100644
index 000000000..b60514e36
--- /dev/null
+++ b/documentation/src/components/particles/particles.tsx
@@ -0,0 +1,290 @@
+/* eslint-disable @typescript-eslint/no-redeclare */
+/* eslint-disable @typescript-eslint/no-shadow */
+/* eslint-disable max-params */
+/* eslint-disable no-plusplus */
+/* eslint-disable @typescript-eslint/no-use-before-define */
+/* eslint-disable no-bitwise */
+/* eslint-disable no-param-reassign */
+import React, { ComponentPropsWithoutRef, useEffect, useRef, useState } from "react";
+import { cn } from "@site/src/lib/utils";
+
+interface MousePosition {
+ x: number;
+ y: number;
+}
+
+function MousePosition(): MousePosition {
+ const [mousePosition, setMousePosition] = useState({
+ x: 0,
+ y: 0,
+ });
+
+ useEffect(() => {
+ const handleMouseMove = (event: MouseEvent) => {
+ setMousePosition({ x: event.clientX, y: event.clientY });
+ };
+
+ window.addEventListener("mousemove", handleMouseMove);
+
+ return () => {
+ window.removeEventListener("mousemove", handleMouseMove);
+ };
+ }, []);
+
+ return mousePosition;
+}
+
+interface ParticlesProps extends ComponentPropsWithoutRef<"div"> {
+ className?: string;
+ quantity?: number;
+ staticity?: number;
+ ease?: number;
+ size?: number;
+ refresh?: boolean;
+ color?: string;
+ vx?: number;
+ vy?: number;
+}
+
+function hexToRgb(hex: string): number[] {
+ hex = hex.replace("#", "");
+
+ if (hex.length === 3) {
+ hex = hex
+ .split("")
+ .map((char) => char + char)
+ .join("");
+ }
+
+ const hexInt = parseInt(hex, 16);
+ const red = (hexInt >> 16) & 255;
+ const green = (hexInt >> 8) & 255;
+ const blue = hexInt & 255;
+ return [red, green, blue];
+}
+
+type Circle = {
+ x: number;
+ y: number;
+ translateX: number;
+ translateY: number;
+ size: number;
+ alpha: number;
+ targetAlpha: number;
+ dx: number;
+ dy: number;
+ magnetism: number;
+};
+
+export const Particles: React.FC = ({
+ className = "",
+ quantity = 100,
+ staticity = 50,
+ ease = 50,
+ size = 0.4,
+ refresh = false,
+ color = "#ffffff",
+ vx = 0,
+ vy = 0,
+ ...props
+}) => {
+ const canvasRef = useRef(null);
+ const canvasContainerRef = useRef(null);
+ const context = useRef(null);
+ const circles = useRef([]);
+ const mousePosition = MousePosition();
+ const mouse = useRef<{ x: number; y: number }>({ x: 0, y: 0 });
+ const canvasSize = useRef<{ w: number; h: number }>({ w: 0, h: 0 });
+ const dpr = typeof window !== "undefined" ? window.devicePixelRatio : 1;
+ const rafID = useRef(null);
+ const resizeTimeout = useRef(null);
+
+ useEffect(() => {
+ if (canvasRef.current) {
+ context.current = canvasRef.current.getContext("2d");
+ }
+ initCanvas();
+ animate();
+
+ const handleResize = () => {
+ if (resizeTimeout.current) {
+ clearTimeout(resizeTimeout.current);
+ }
+ resizeTimeout.current = setTimeout(() => {
+ initCanvas();
+ }, 200);
+ };
+
+ window.addEventListener("resize", handleResize);
+
+ return () => {
+ if (rafID.current != null) {
+ window.cancelAnimationFrame(rafID.current);
+ }
+ if (resizeTimeout.current) {
+ clearTimeout(resizeTimeout.current);
+ }
+ window.removeEventListener("resize", handleResize);
+ };
+ }, [color]);
+
+ useEffect(() => {
+ onMouseMove();
+ }, [mousePosition.x, mousePosition.y]);
+
+ useEffect(() => {
+ initCanvas();
+ }, [refresh]);
+
+ const initCanvas = () => {
+ resizeCanvas();
+ drawParticles();
+ };
+
+ const onMouseMove = () => {
+ if (canvasRef.current) {
+ const rect = canvasRef.current.getBoundingClientRect();
+ const { w, h } = canvasSize.current;
+ const x = mousePosition.x - rect.left - w / 2;
+ const y = mousePosition.y - rect.top - h / 2;
+ const inside = x < w / 2 && x > -w / 2 && y < h / 2 && y > -h / 2;
+ if (inside) {
+ mouse.current.x = x;
+ mouse.current.y = y;
+ }
+ }
+ };
+
+ const resizeCanvas = () => {
+ if (canvasContainerRef.current && canvasRef.current && context.current) {
+ canvasSize.current.w = canvasContainerRef.current.offsetWidth;
+ canvasSize.current.h = canvasContainerRef.current.offsetHeight;
+
+ canvasRef.current.width = canvasSize.current.w * dpr;
+ canvasRef.current.height = canvasSize.current.h * dpr;
+ canvasRef.current.style.width = `${canvasSize.current.w}px`;
+ canvasRef.current.style.height = `${canvasSize.current.h}px`;
+ context.current.scale(dpr, dpr);
+
+ // Clear existing particles and create new ones with exact quantity
+ circles.current = [];
+ for (let i = 0; i < quantity; i++) {
+ const circle = circleParams();
+ drawCircle(circle);
+ }
+ }
+ };
+
+ const circleParams = (): Circle => {
+ const x = Math.floor(Math.random() * canvasSize.current.w);
+ const y = Math.floor(Math.random() * canvasSize.current.h);
+ const translateX = 0;
+ const translateY = 0;
+ const pSize = Math.floor(Math.random() * 2) + size;
+ const alpha = 0;
+ const targetAlpha = parseFloat((Math.random() * 0.6 + 0.1).toFixed(1));
+ const dx = (Math.random() - 0.5) * 0.1;
+ const dy = (Math.random() - 0.5) * 0.1;
+ const magnetism = 0.1 + Math.random() * 4;
+ return {
+ x,
+ y,
+ translateX,
+ translateY,
+ size: pSize,
+ alpha,
+ targetAlpha,
+ dx,
+ dy,
+ magnetism,
+ };
+ };
+
+ const rgb = hexToRgb(color);
+
+ const drawCircle = (circle: Circle, update = false) => {
+ if (context.current) {
+ const { x, y, translateX, translateY, size, alpha } = circle;
+ context.current.translate(translateX, translateY);
+ context.current.beginPath();
+ context.current.arc(x, y, size, 0, 2 * Math.PI);
+ context.current.fillStyle = `rgba(${rgb.join(", ")}, ${alpha})`;
+ context.current.fill();
+ context.current.setTransform(dpr, 0, 0, dpr, 0, 0);
+
+ if (!update) {
+ circles.current.push(circle);
+ }
+ }
+ };
+
+ const clearContext = () => {
+ if (context.current) {
+ context.current.clearRect(0, 0, canvasSize.current.w, canvasSize.current.h);
+ }
+ };
+
+ const drawParticles = () => {
+ clearContext();
+ const particleCount = quantity;
+ for (let i = 0; i < particleCount; i++) {
+ const circle = circleParams();
+ drawCircle(circle);
+ }
+ };
+
+ const remapValue = (value: number, start1: number, end1: number, start2: number, end2: number): number => {
+ const remapped = ((value - start1) * (end2 - start2)) / (end1 - start1) + start2;
+ return remapped > 0 ? remapped : 0;
+ };
+
+ const animate = () => {
+ clearContext();
+ circles.current.forEach((circle: Circle, i: number) => {
+ // Handle the alpha value
+ const edge = [
+ circle.x + circle.translateX - circle.size, // distance from left edge
+ canvasSize.current.w - circle.x - circle.translateX - circle.size, // distance from right edge
+ circle.y + circle.translateY - circle.size, // distance from top edge
+ canvasSize.current.h - circle.y - circle.translateY - circle.size, // distance from bottom edge
+ ];
+ const closestEdge = edge.reduce((a, b) => Math.min(a, b));
+ const remapClosestEdge = parseFloat(remapValue(closestEdge, 0, 20, 0, 1).toFixed(2));
+ if (remapClosestEdge > 1) {
+ circle.alpha += 0.02;
+ if (circle.alpha > circle.targetAlpha) {
+ circle.alpha = circle.targetAlpha;
+ }
+ } else {
+ circle.alpha = circle.targetAlpha * remapClosestEdge;
+ }
+ circle.x += circle.dx + vx;
+ circle.y += circle.dy + vy;
+ circle.translateX += (mouse.current.x / (staticity / circle.magnetism) - circle.translateX) / ease;
+ circle.translateY += (mouse.current.y / (staticity / circle.magnetism) - circle.translateY) / ease;
+
+ drawCircle(circle, true);
+
+ // circle gets out of the canvas
+ if (
+ circle.x < -circle.size ||
+ circle.x > canvasSize.current.w + circle.size ||
+ circle.y < -circle.size ||
+ circle.y > canvasSize.current.h + circle.size
+ ) {
+ // remove the circle from the array
+ circles.current.splice(i, 1);
+ // create a new circle
+ const newCircle = circleParams();
+ drawCircle(newCircle);
+ }
+ });
+ rafID.current = window.requestAnimationFrame(animate);
+ };
+
+ return (
+
+
+
+ );
+};
diff --git a/documentation/src/components/partners/partners.module.css b/documentation/src/components/partners/partners.module.css
deleted file mode 100644
index cc073f446..000000000
--- a/documentation/src/components/partners/partners.module.css
+++ /dev/null
@@ -1,75 +0,0 @@
-.container {
- margin: 0 0 120px;
-}
-
-.contact {
- display: flex;
- justify-content: center;
-}
-
-.sponsors {
- margin-top: 50px;
- display: grid;
- grid-template-columns: 1fr 1fr 1fr;
- gap: 10px 20px;
-}
-
-.card {
- transition: all 200ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;
- border-radius: 10px;
- border: 1px dashed #ffc4268f;
- background-color: #ffc52617;
- padding: 20px;
- display: flex;
- align-items: center;
- cursor: pointer;
-}
-
-.plus {
- display: flex;
- align-items: center;
- justify-content: center;
- margin: 0px 20px 0px 0px;
- font-size: 1.5rem;
- padding: 8px;
- height: 34px;
- width: 34px;
- border-radius: 10px;
- border: 1px solid var(--ifm-color-warning-light);
- background: #ffc5261e;
-}
-
-.plus svg {
- width: 100%;
- height: 100%;
- fill: var(--ifm-color-warning-light);
-}
-
-.content {
-}
-
-.title {
- font-size: 1.1rem;
- color: var(--ifm-font-color-base) !important;
-}
-
-.description {
- font-weight: 500;
- font-size: 0.8rem;
- color: var(--ifm-color-emphasis-600);
-}
-
-@media (max-width: 996px) {
- .sponsors {
- margin-top: 50px;
- display: flex;
- flex-direction: column;
- gap: 20px 20px;
- justify-content: center;
- align-items: center;
- }
- .card {
- max-width: 420px;
- width: 100%;
- }
-}
diff --git a/documentation/src/components/partners/partners.tsx b/documentation/src/components/partners/partners.tsx
deleted file mode 100644
index c55449877..000000000
--- a/documentation/src/components/partners/partners.tsx
+++ /dev/null
@@ -1,67 +0,0 @@
-import React from "react";
-import clsx from "clsx";
-
-import styles from "./partners.module.css";
-
-export function Partners(): JSX.Element {
- return (
-
-
-
Be our partner.
-
- BetterTyped was created to make the best open-source tools – an extremely demanding task. Would you like to
- partner with us or sponsor our work?
-
-
-
-
-
- );
-}
diff --git a/documentation/src/components/presentation/presentation.tsx b/documentation/src/components/presentation/presentation.tsx
new file mode 100644
index 000000000..cd9afa47d
--- /dev/null
+++ b/documentation/src/components/presentation/presentation.tsx
@@ -0,0 +1,18 @@
+import clsx from "clsx";
+
+export const Presentation = ({ children, className }: { children?: React.ReactNode; className?: string }) => {
+ return (
+
+
+
+
+ {children}
+
+ );
+};
diff --git a/documentation/src/components/preview/preview.module.css b/documentation/src/components/preview/preview.module.css
deleted file mode 100644
index b48c38d0f..000000000
--- a/documentation/src/components/preview/preview.module.css
+++ /dev/null
@@ -1,9 +0,0 @@
-.container {
- margin: 0 0 80px;
-}
-
-.contact {
- display: flex;
- justify-content: center;
- min-height: 600px;
-}
diff --git a/documentation/src/components/preview/preview.tsx b/documentation/src/components/preview/preview.tsx
deleted file mode 100644
index e5a2c6972..000000000
--- a/documentation/src/components/preview/preview.tsx
+++ /dev/null
@@ -1,28 +0,0 @@
-/* eslint-disable react/no-unescaped-entities */
-import React from "react";
-import clsx from "clsx";
-
-import styles from "./preview.module.css";
-
-export function Preview(): JSX.Element {
- return (
-
-
-
Simpler. Faster. Better.
-
- Reduce the time needed to handle state and reducers. Streamline HTTP adapter setup and its dependencies.
- Everything is set up right after installation in a fully configured environment with no external dependencies!
-
-
-
-
-
-
- );
-}
diff --git a/documentation/src/components/promotion/promotion.module.css b/documentation/src/components/promotion/promotion.module.css
deleted file mode 100644
index 376375c63..000000000
--- a/documentation/src/components/promotion/promotion.module.css
+++ /dev/null
@@ -1,35 +0,0 @@
-.container {
- padding: 80px 0;
- background: #dfdfdf;
- border-top: 1px solid var(--ifm-color-secondary-dark);
- border-bottom: 1px solid var(--ifm-color-secondary-dark);
- background-image: radial-gradient(var(--ifm-color-emphasis-500) 1px, transparent 1px),
- radial-gradient(var(--ifm-color-emphasis-500) 1px, transparent 1px);
- background-position: 0 0, 60px 60px;
- background-size: 30px 30px;
-}
-
-html[data-theme="dark"] .container {
- background-color: var(--section-background);
- border-top: 1px solid var(--ifm-toc-border-color);
- border-bottom: 1px solid var(--ifm-toc-border-color);
- background-image: radial-gradient(rgba(0, 0, 0, 0.05), 1.3px, transparent 1.3px),
- radial-gradient(rgba(0, 0, 0, 0.05), 1.3px, transparent 1.3px);
-}
-
-.row {
- display: flex;
- align-items: center;
- justify-content: space-between;
- gap: 20px;
- flex-wrap: wrap;
-}
-
-.title {
- font-size: 30px;
- font-weight: 900;
-}
-
-.title span {
- color: var(--ifm-color-primary);
-}
diff --git a/documentation/src/components/promotion/promotion.tsx b/documentation/src/components/promotion/promotion.tsx
deleted file mode 100644
index 2c894f246..000000000
--- a/documentation/src/components/promotion/promotion.tsx
+++ /dev/null
@@ -1,31 +0,0 @@
-import React from "react";
-import clsx from "clsx";
-
-import styles from "./promotion.module.css";
-
-export function Promotion(): JSX.Element {
- return (
-
- );
-}
diff --git a/documentation/src/components/scale-in/index.ts b/documentation/src/components/scale-in/index.ts
new file mode 100644
index 000000000..ec35ce387
--- /dev/null
+++ b/documentation/src/components/scale-in/index.ts
@@ -0,0 +1 @@
+export * from "./scale-in";
diff --git a/documentation/src/components/scale-in/scale-in.tsx b/documentation/src/components/scale-in/scale-in.tsx
new file mode 100644
index 000000000..b7f420e7e
--- /dev/null
+++ b/documentation/src/components/scale-in/scale-in.tsx
@@ -0,0 +1,70 @@
+import React from "react";
+import { useActors, useMakeup, Stage, StyleOptions } from "@react-theater/scroll";
+
+const ScaleInContent = ({
+ children,
+ start = 0.05,
+ end = 0.25,
+ scale = 5,
+ setActorStyle,
+}: {
+ children: React.ReactNode;
+ start?: number;
+ end?: number;
+ scale?: number;
+ setActorStyle: (style: StyleOptions) => void;
+}) => {
+ // Change
+ useActors([
+ {
+ start: 0,
+ end: start,
+ screen: true,
+ onUpdate: () => {
+ setActorStyle({
+ opacity: 0,
+ });
+ },
+ },
+ {
+ start,
+ end,
+ screen: true,
+ onUpdate: ({ progress }) => {
+ setActorStyle({
+ opacity: progress,
+ scale: scale - (scale - 1) * progress,
+ });
+ },
+ },
+ ]);
+
+ return children;
+};
+
+export const ScaleIn = ({
+ children,
+ start,
+ end,
+ scale,
+ className,
+ isStage = true,
+ ...rest
+}: {
+ children: React.ReactNode;
+ start?: number;
+ end?: number;
+ scale?: number;
+ isStage?: boolean;
+} & React.HTMLProps) => {
+ const [actorRef, setActorStyle] = useMakeup();
+ const Component = isStage ? Stage : "div";
+
+ return (
+
+
+ {children}
+
+
+ );
+};
diff --git a/documentation/src/components/scale-out/index.ts b/documentation/src/components/scale-out/index.ts
new file mode 100644
index 000000000..6a2073871
--- /dev/null
+++ b/documentation/src/components/scale-out/index.ts
@@ -0,0 +1 @@
+export * from "./scale-out";
diff --git a/documentation/src/components/scale-out/scale-out.tsx b/documentation/src/components/scale-out/scale-out.tsx
new file mode 100644
index 000000000..830b133ad
--- /dev/null
+++ b/documentation/src/components/scale-out/scale-out.tsx
@@ -0,0 +1,71 @@
+import React from "react";
+import { useActors, useMakeup, Stage, StyleOptions } from "@react-theater/scroll";
+
+const ScaleOutContent = ({
+ children,
+ start = 0.01,
+ end = 0.55,
+ scale = 1,
+ setActorStyle,
+}: {
+ children: React.ReactNode;
+ start?: number;
+ end?: number;
+ scale?: number;
+ setActorStyle: (style: StyleOptions) => void;
+}) => {
+ // Change
+ useActors([
+ {
+ start: 0,
+ end: start,
+ screen: true,
+ onUpdate: () => {
+ setActorStyle({
+ opacity: 0,
+ scale: 0.4,
+ });
+ },
+ },
+ {
+ start,
+ end,
+ screen: true,
+ onUpdate: ({ progress }) => {
+ setActorStyle({
+ opacity: progress,
+ scale: 0.4 + (scale - 0.4) * progress,
+ });
+ },
+ },
+ ]);
+
+ return children;
+};
+
+export const ScaleOut = ({
+ children,
+ start,
+ end,
+ scale,
+ className,
+ isStage = true,
+ ...rest
+}: {
+ children: React.ReactNode;
+ start?: number;
+ end?: number;
+ scale?: number;
+ isStage?: boolean;
+} & React.HTMLProps) => {
+ const [actorRef, setActorStyle] = useMakeup();
+ const Component = isStage ? Stage : "div";
+
+ return (
+
+
+ {children}
+
+
+ );
+};
diff --git a/documentation/src/components/show-more/show-more.tsx b/documentation/src/components/show-more/show-more.tsx
new file mode 100644
index 000000000..853b932f2
--- /dev/null
+++ b/documentation/src/components/show-more/show-more.tsx
@@ -0,0 +1,41 @@
+import { cn } from "@site/src/lib/utils";
+import React, { useState, useRef } from "react";
+
+interface ShowMoreProps {
+ children: React.ReactNode;
+ collapsedHeight?: number; // px
+ buttonClassName?: string;
+}
+
+export const ShowMore: React.FC = ({ children, collapsedHeight = 400, buttonClassName = "" }) => {
+ const [expanded, setExpanded] = useState(false);
+ const contentRef = useRef(null);
+
+ return (
+
+
+ {children}
+ {/* Gradient overlay when collapsed */}
+ {!expanded && (
+
+ )}
+
+ {/* Show more/less button */}
+
+ setExpanded((v) => !v)}
+ >
+ {expanded ? "Show less" : "Show more"}
+
+
+
+ );
+};
diff --git a/documentation/src/components/sidebar-menu/sidebar-menu.tsx b/documentation/src/components/sidebar-menu/sidebar-menu.tsx
new file mode 100644
index 000000000..74fe17d0c
--- /dev/null
+++ b/documentation/src/components/sidebar-menu/sidebar-menu.tsx
@@ -0,0 +1,83 @@
+/* eslint-disable react/no-array-index-key */
+import Link from "@docusaurus/Link";
+import { SidebarItem, useSidebar } from "@site/src/hooks/use-sidebar";
+import { cn } from "@site/src/lib/utils";
+import Search from "@theme/NavbarItem/SearchNavbarItem";
+
+const getColor = (item: SidebarItem) => {
+ return item.active
+ ? item.section
+ : {
+ text: `text-zinc-500 dark:text-zinc-400`,
+ textHover: item.section.textHover,
+ textAction: item.section.textAction,
+ icon: `group-hover:shadow-zinc-200 dark:group-hover:bg-zinc-500 bg-zinc-400 dark:bg-zinc-500`,
+ iconHover: item.section.iconHover,
+ active: false,
+ };
+};
+
+export const SidebarMenu = () => {
+ const { sidebar, activeItem } = useSidebar();
+
+ return (
+
+
+
+
+
+ {activeItem && (
+
+
+ {sidebar.map((item, index) => {
+ const color = getColor(item);
+ return (
+
+
+
+
+
+ {item.name}
+ {item.isPro && (
+
+ Pro
+
+ )}
+ {item.isNew && (
+
+ New
+
+ )}
+
+
+ );
+ })}
+
+
+
+ )}
+
+
+ );
+};
diff --git a/documentation/src/components/soon/index.ts b/documentation/src/components/soon/index.ts
new file mode 100644
index 000000000..9f4abf506
--- /dev/null
+++ b/documentation/src/components/soon/index.ts
@@ -0,0 +1 @@
+export * from "./soon";
diff --git a/documentation/src/components/soon/soon.tsx b/documentation/src/components/soon/soon.tsx
new file mode 100644
index 000000000..7cec53e16
--- /dev/null
+++ b/documentation/src/components/soon/soon.tsx
@@ -0,0 +1,7 @@
+export const Soon = () => {
+ return (
+
+ Coming soon
+
+ );
+};
diff --git a/documentation/src/components/title/index.ts b/documentation/src/components/title/index.ts
new file mode 100644
index 000000000..ce66ba29d
--- /dev/null
+++ b/documentation/src/components/title/index.ts
@@ -0,0 +1 @@
+export * from "./title";
diff --git a/documentation/src/components/title/title.tsx b/documentation/src/components/title/title.tsx
new file mode 100644
index 000000000..58eae4eca
--- /dev/null
+++ b/documentation/src/components/title/title.tsx
@@ -0,0 +1,53 @@
+import { Children, forwardRef } from "react";
+
+export const Title = forwardRef(
+ (
+ props: Omit, "size"> & {
+ as?: "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "span";
+ size?: "lg" | "md" | "sm" | "none";
+ wrapperClass?: string;
+ },
+ ref,
+ ) => {
+ const { as = "h2", className = "", wrapperClass = "", size = "md", ...rest } = props;
+
+ const colorClass =
+ "from-zinc-800/60 via-zinc-800 to-zinc-800/60 dark:from-zinc-200/60 dark:via-zinc-200 dark:to-zinc-200/60";
+
+ const sizeClass = {
+ lg: "text-4xl sm:text-5xl md:text-5xl lg:text-6xl",
+ md: "text-4xl sm:text-4xl md:text-5xl lg:text-5xl",
+ sm: "text-3xl sm:text-3xl md:text-4xl lg:text-4xl",
+ xs: "text-xl",
+ none: "",
+ }[size];
+
+ const Component = as;
+ const newChildren = Children.map(props.children, (child) => {
+ if (typeof child === "string") {
+ return child.split(" ").map((part, index) => (
+
+ {part}{" "}
+
+ ));
+ }
+ return child;
+ });
+
+ return (
+
+ {newChildren}
+
+ );
+ },
+);
diff --git a/documentation/src/components/ui/animated-list-item.tsx b/documentation/src/components/ui/animated-list-item.tsx
new file mode 100644
index 000000000..d07136e9c
--- /dev/null
+++ b/documentation/src/components/ui/animated-list-item.tsx
@@ -0,0 +1,54 @@
+import React from "react";
+import { motion, AnimatePresence } from "framer-motion";
+import { cn } from "@site/src/lib/utils";
+
+const animationsTop = {
+ initial: { scale: 0.7, opacity: 0, y: -60 },
+ animate: { scale: 1, opacity: 1, y: 0 },
+ exit: { scale: 0.7, opacity: 0, y: 60 },
+ transition: { type: "spring", stiffness: 350, damping: 40 },
+};
+const animationsBottom = {
+ initial: { scale: 0.7, opacity: 0, y: 60 },
+ animate: { scale: 1, opacity: 1, y: 0 },
+ exit: { scale: 0.7, opacity: 0, y: -60 },
+ transition: { type: "spring", stiffness: 350, damping: 40 },
+};
+
+const animations = {
+ top: animationsTop,
+ bottom: animationsBottom,
+};
+
+export function AnimatedListItem({
+ children,
+ position = "top",
+ className,
+ open = true,
+}: {
+ children: React.ReactNode;
+ position?: "top" | "bottom";
+ className?: string;
+ open?: boolean;
+}) {
+ const ref = React.useRef(null);
+ const { initial, animate, exit, transition } = animations[position];
+
+ return (
+
+ {open && (
+
+ {children}
+
+ )}
+
+ );
+}
diff --git a/documentation/src/components/ui/docs-card.tsx b/documentation/src/components/ui/docs-card.tsx
new file mode 100644
index 000000000..89d5faeb7
--- /dev/null
+++ b/documentation/src/components/ui/docs-card.tsx
@@ -0,0 +1,41 @@
+import { ComponentProps } from "react";
+import { cva } from "class-variance-authority";
+import { cn } from "@site/src/lib/utils";
+
+const linkCardVariants = cva(
+ [
+ "relative flex flex-col gap-2 rounded-xl transition-all duration-200",
+ "!no-underline [&:*]:no-underline overflow-hidden border",
+ "focus:ring-3 focus:ring-primary-500 dark:focus:ring-primary-400 focus:ring-offset-0 focus:outline-none",
+ ],
+ {
+ variants: {
+ variant: {
+ default: cn(
+ "bg-gradient-to-br from-zinc-50 to-zinc-100 border-zinc-200 text-zinc-900",
+ "dark:bg-gradient-to-br dark:from-zinc-900 dark:to-zinc-800 dark:border-zinc-700 dark:text-zinc-100",
+ ),
+ },
+ hover: {
+ true: [
+ "cursor-pointer",
+ "hover:from-zinc-200 hover:via-zinc-100 hover:to-zinc-50 hover:border-zinc-40 hover:ring-2 hover:ring-zinc-300",
+ "dark:hover:from-zinc-700 dark:hover:via-zinc-800 dark:hover:to-zinc-900 dark:hover:border-zinc-500 dark:hover:ring-2 dark:hover:ring-zinc-700",
+ ].join(" "),
+ false: "",
+ },
+ animateIn: {
+ true: "animate-in fade-in-0 duration-300 scale-90 animate-scale-in",
+ false: "",
+ },
+ },
+ },
+);
+
+/**
+ * Used for the docs to be able to manage all of the future and past styles
+ * When we will pack something in the versioned docs it will not cause some issues
+ */
+export const DocsCard = ({ hover = true, className, ...props }: ComponentProps<"div"> & { hover?: boolean }) => {
+ return
;
+};
diff --git a/documentation/src/components/ui/dot-pattern.tsx b/documentation/src/components/ui/dot-pattern.tsx
new file mode 100644
index 000000000..533ebca52
--- /dev/null
+++ b/documentation/src/components/ui/dot-pattern.tsx
@@ -0,0 +1,150 @@
+/* eslint-disable @typescript-eslint/no-shadow */
+import { cn } from "@site/src/lib/utils";
+import { motion } from "motion/react";
+import React, { useEffect, useId, useRef, useState } from "react";
+
+/**
+ * DotPattern Component Props
+ *
+ * @param {number} [width=16] - The horizontal spacing between dots
+ * @param {number} [height=16] - The vertical spacing between dots
+ * @param {number} [x=0] - The x-offset of the entire pattern
+ * @param {number} [y=0] - The y-offset of the entire pattern
+ * @param {number} [cx=1] - The x-offset of individual dots
+ * @param {number} [cy=1] - The y-offset of individual dots
+ * @param {number} [cr=1] - The radius of each dot
+ * @param {string} [className] - Additional CSS classes to apply to the SVG container
+ * @param {boolean} [glow=false] - Whether dots should have a glowing animation effect
+ */
+interface DotPatternProps extends React.SVGProps {
+ width?: number;
+ height?: number;
+ x?: number;
+ y?: number;
+ cx?: number;
+ cy?: number;
+ cr?: number;
+ className?: string;
+ glow?: boolean;
+ [key: string]: unknown;
+}
+
+/**
+ * DotPattern Component
+ *
+ * A React component that creates an animated or static dot pattern background using SVG.
+ * The pattern automatically adjusts to fill its container and can optionally display glowing dots.
+ *
+ * @component
+ *
+ * @see DotPatternProps for the props interface.
+ *
+ * @example
+ * // Basic usage
+ *
+ *
+ * // With glowing effect and custom spacing
+ *
+ *
+ * @notes
+ * - The component is client-side only ("use client")
+ * - Automatically responds to container size changes
+ * - When glow is enabled, dots will animate with random delays and durations
+ * - Uses Motion for animations
+ * - Dots color can be controlled via the text color utility classes
+ */
+
+export function DotPattern({
+ width = 16,
+ height = 16,
+ cx = 1,
+ cy = 1,
+ cr = 1,
+ className,
+ glow = false,
+ ...props
+}: DotPatternProps) {
+ const id = useId();
+ const containerRef = useRef(null);
+ const [dimensions, setDimensions] = useState({ width: 0, height: 0 });
+
+ useEffect(() => {
+ const updateDimensions = () => {
+ if (containerRef.current) {
+ const { width, height } = containerRef.current.getBoundingClientRect();
+ setDimensions({ width, height });
+ }
+ };
+
+ updateDimensions();
+ window.addEventListener("resize", updateDimensions);
+ return () => window.removeEventListener("resize", updateDimensions);
+ }, []);
+
+ const dots = Array.from(
+ {
+ length: Math.ceil(dimensions.width / width) * Math.ceil(dimensions.height / height),
+ },
+ (_, i) => {
+ const col = i % Math.ceil(dimensions.width / width);
+ const row = Math.floor(i / Math.ceil(dimensions.width / width));
+ return {
+ x: col * width + cx,
+ y: row * height + cy,
+ delay: Math.random() * 5,
+ duration: Math.random() * 3 + 2,
+ };
+ },
+ );
+
+ return (
+
+
+
+
+
+
+
+ {dots.map((dot) => (
+
+ ))}
+
+ );
+}
diff --git a/documentation/src/components/ui/noise.tsx b/documentation/src/components/ui/noise.tsx
new file mode 100644
index 000000000..fe0e11aed
--- /dev/null
+++ b/documentation/src/components/ui/noise.tsx
@@ -0,0 +1,31 @@
+import { cn } from "@site/src/lib/utils";
+import noise from "@site/static/img/noise.webp";
+import { ComponentProps } from "react";
+
+const visibilityMap = {
+ low: "dark:opacity-[0.02] opacity-[0.1] brightness-[0.4] dark:brightness-[1]",
+ medium: "dark:opacity-[0.05] opacity-[0.15] brightness-[0.4] dark:brightness-[1]",
+ high: "dark:opacity-[0.1] opacity-[0.2] brightness-[0.4] dark:brightness-[1]",
+};
+
+export const Noise = (props: ComponentProps<"div"> & { visibility?: keyof typeof visibilityMap }) => {
+ const { visibility = "low" } = props;
+
+ return (
+
+ );
+};
diff --git a/documentation/src/components/ui/rainbow-button.tsx b/documentation/src/components/ui/rainbow-button.tsx
new file mode 100644
index 000000000..f080d0024
--- /dev/null
+++ b/documentation/src/components/ui/rainbow-button.tsx
@@ -0,0 +1,45 @@
+import React from "react";
+import { cn } from "@site/src/lib/utils";
+import { ChevronRight } from "lucide-react";
+import Link from "@docusaurus/Link";
+
+interface RainbowButtonProps extends React.ButtonHTMLAttributes {
+ navbarIcon?: boolean;
+}
+
+const style = {
+ color: "white",
+};
+
+export const RainbowButton = React.forwardRef(
+ ({ children, className, navbarIcon, ...props }, ref) => {
+ const Component = navbarIcon ? Link : "button";
+
+ return (
+
+ {children}
+ {navbarIcon && }
+
+ );
+ },
+);
+
+RainbowButton.displayName = "RainbowButton";
diff --git a/documentation/src/components/ui/shine-beam.tsx b/documentation/src/components/ui/shine-beam.tsx
new file mode 100644
index 000000000..cae926dee
--- /dev/null
+++ b/documentation/src/components/ui/shine-beam.tsx
@@ -0,0 +1,61 @@
+import * as React from "react";
+import { cn } from "@site/src/lib/utils";
+
+interface ShineBorderProps extends React.HTMLAttributes {
+ /**
+ * Width of the border in pixels
+ * @default 1
+ */
+ borderWidth?: number;
+ /**
+ * Duration of the animation in seconds
+ * @default 14
+ */
+ duration?: number;
+ /**
+ * Color of the border, can be a single color or an array of colors
+ * @default "#000000"
+ */
+ shineColor?: string | string[];
+}
+
+/**
+ * Shine Border
+ *
+ * An animated background border effect component with configurable properties.
+ */
+export function ShineBorder({
+ borderWidth = 1,
+ duration = 14,
+ shineColor = "#000000",
+ className,
+ style,
+ ...props
+}: ShineBorderProps) {
+ return (
+
+ );
+}
diff --git a/documentation/src/components/ui/shiny-btn.tsx b/documentation/src/components/ui/shiny-btn.tsx
new file mode 100644
index 000000000..cdd54837d
--- /dev/null
+++ b/documentation/src/components/ui/shiny-btn.tsx
@@ -0,0 +1,66 @@
+"use client";
+
+import { cn } from "@site/src/lib/utils";
+import { motion, MotionProps, type AnimationProps } from "motion/react";
+import React from "react";
+
+const animationProps = {
+ initial: { "--x": "100%", scale: 0.8 },
+ animate: { "--x": "-100%", scale: 1 },
+ whileTap: { scale: 0.95 },
+ transition: {
+ repeat: Infinity,
+ repeatType: "loop",
+ repeatDelay: 1,
+ type: "spring",
+ stiffness: 20,
+ damping: 15,
+ mass: 2,
+ scale: {
+ type: "spring",
+ stiffness: 200,
+ damping: 5,
+ mass: 0.5,
+ },
+ },
+} as AnimationProps;
+
+interface ShinyButtonProps extends Omit, keyof MotionProps>, MotionProps {
+ children: React.ReactNode;
+ className?: string;
+}
+
+export const ShinyButton = React.forwardRef(
+ ({ children, className, ...props }, ref) => {
+ return (
+
+
+ {children}
+
+
+
+ );
+ },
+);
+
+ShinyButton.displayName = "ShinyButton";
diff --git a/documentation/src/components/ui/tabs.tsx b/documentation/src/components/ui/tabs.tsx
new file mode 100644
index 000000000..2476202d1
--- /dev/null
+++ b/documentation/src/components/ui/tabs.tsx
@@ -0,0 +1,54 @@
+"use client";
+
+import * as React from "react";
+import * as TabsPrimitive from "@radix-ui/react-tabs";
+import { cn } from "@site/src/lib/utils";
+
+const Tabs = TabsPrimitive.Root;
+
+const TabsList = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+));
+TabsList.displayName = TabsPrimitive.List.displayName;
+
+const TabsTrigger = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+));
+TabsTrigger.displayName = TabsPrimitive.Trigger.displayName;
+
+const TabsContent = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+));
+TabsContent.displayName = TabsPrimitive.Content.displayName;
+
+export { Tabs, TabsList, TabsTrigger, TabsContent };
diff --git a/documentation/src/components/ui/toast.tsx b/documentation/src/components/ui/toast.tsx
new file mode 100644
index 000000000..4317008f4
--- /dev/null
+++ b/documentation/src/components/ui/toast.tsx
@@ -0,0 +1,157 @@
+"use client";
+
+import * as React from "react";
+import * as ToastPrimitives from "@radix-ui/react-toast";
+import { cva, type VariantProps } from "class-variance-authority";
+import { X } from "lucide-react";
+import { cn } from "@site/src/lib/utils";
+import { useToast } from "@site/src/hooks/use-toast";
+import { AnimatePresence } from "motion/react";
+
+import { AnimatedListItem } from "./animated-list-item";
+
+const ToastProvider = ToastPrimitives.Provider;
+
+const ToastViewport = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+));
+ToastViewport.displayName = ToastPrimitives.Viewport.displayName;
+
+const toastVariants = cva(
+ [
+ "relative flex flex-col gap-2 rounded-xl transition-all duration-200",
+ "!no-underline [&:*]:no-underline overflow-hidden border !p-0 !mb-0.5",
+ "focus:ring-3 focus:ring-primary-500 dark:focus:ring-primary-400 focus:ring-offset-0 focus:outline-none",
+ ],
+ {
+ variants: {
+ variant: {
+ default: cn(
+ "bg-gradient-to-br from-zinc-50 to-zinc-100 border-zinc-200 text-zinc-900",
+ "dark:bg-gradient-to-br dark:from-zinc-900 dark:to-zinc-800 dark:border-zinc-700 dark:text-zinc-100",
+ ),
+ destructive: "destructive group border-destructive bg-destructive text-destructive-foreground",
+ },
+ hover: {
+ true: [
+ "cursor-pointer",
+ "hover:from-zinc-200 hover:via-zinc-100 hover:to-zinc-50 hover:border-zinc-40 hover:ring-2 hover:ring-zinc-300",
+ "dark:hover:from-zinc-700 dark:hover:via-zinc-800 dark:hover:to-zinc-900 dark:hover:border-zinc-500 dark:hover:ring-2 dark:hover:ring-zinc-700",
+ ].join(" "),
+ false: "",
+ },
+ },
+ defaultVariants: {
+ variant: "default",
+ hover: true,
+ },
+ },
+);
+
+const Toast = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef & VariantProps
+>(({ className, variant, ...props }, ref) => {
+ return ;
+});
+Toast.displayName = ToastPrimitives.Root.displayName;
+
+const ToastAction = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+));
+ToastAction.displayName = ToastPrimitives.Action.displayName;
+
+const ToastClose = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+
+
+));
+ToastClose.displayName = ToastPrimitives.Close.displayName;
+
+const ToastTitle = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+));
+ToastTitle.displayName = ToastPrimitives.Title.displayName;
+
+const ToastDescription = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+));
+ToastDescription.displayName = ToastPrimitives.Description.displayName;
+
+type ToastProps = Omit, "title" | "description"> & {
+ message: React.ReactNode;
+};
+
+type ToastActionElement = React.ReactElement;
+
+export {
+ type ToastProps,
+ type ToastActionElement,
+ ToastProvider,
+ ToastViewport,
+ Toast,
+ ToastTitle,
+ ToastDescription,
+ ToastClose,
+ ToastAction,
+};
+
+export function Toaster() {
+ const { toasts } = useToast();
+
+ return (
+
+
+ {toasts?.map(({ id, message, timestamp, ...props }) => {
+ return (
+
+
+ {message}
+
+
+
+ );
+ })}
+
+
+
+
+ );
+}
diff --git a/documentation/src/css/custom.css b/documentation/src/css/custom.css
index 5d71cc6a2..0aa3930ca 100644
--- a/documentation/src/css/custom.css
+++ b/documentation/src/css/custom.css
@@ -1,3 +1,1333 @@
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
+
+html body {
+ --color-1: 0 100% 63%;
+ --color-2: 270 100% 63%;
+ --color-3: 210 100% 63%;
+ --color-4: 195 100% 63%;
+ --color-5: 90 100% 63%;
+
+ --docsearch-text-color: theme(colors.zinc.100);
+ --docsearch-container-background: rgba(9, 10, 17, 0.7);
+ --docsearch-modal-background: theme(colors.zinc.900/20);
+ --docsearch-modal-shadow: inset 1px 1px 0 0 theme(colors.zinc.800), 0 3px 8px 0 theme(colors.zinc.950/20);
+ --docsearch-searchbox-background: theme(colors.zinc.950);
+ --docsearch-searchbox-focus-background: theme(colors.zinc.900);
+ --docsearch-hit-color: theme(colors.zinc.400);
+ --docsearch-hit-shadow: none;
+ --docsearch-hit-background: theme(colors.zinc.950);
+ --docsearch-key-gradient: linear-gradient(-26.5deg, theme(colors.zinc.600), theme(colors.zinc.800));
+ --docsearch-key-shadow:
+ inset 0 -2px 0 0 theme(colors.zinc.800), inset 0 0 1px 1px theme(colors.zinc.700),
+ 0 2px 2px 0 theme(colors.zinc.900/30);
+ --docsearch-key-pressed-shadow:
+ inset 0 -2px 0 0 theme(colors.zinc.800), inset 0 0 1px 1px theme(colors.zinc.700),
+ 0 1px 1px 0 theme(colors.zinc.900/30);
+ --docsearch-footer-background: theme(colors.zinc.800);
+ --docsearch-footer-shadow: inset 0 1px 0 0 theme(colors.zinc.400/50), 0 -4px 8px 0 theme(colors.zinc.900/20);
+ --docsearch-logo-color: theme(colors.zinc.100);
+ --docsearch-muted-color: theme(colors.zinc.500);
+ --docsearch-highlight-color: theme(colors.cyan.500);
+}
+
+.tabs-container {
+ @apply !w-full !flex !flex-col;
+}
+.tabs-container ul {
+ @apply !bg-zinc-100 dark:bg-zinc-800 !text-zinc-500 dark:!text-zinc-400 !inline-flex !h-9 !w-fit !items-center !justify-center !rounded-lg !p-1 !m-0 !important;
+ list-style: none;
+ border: none;
+ box-shadow: none;
+}
+.tabs-container ul li {
+ @apply flex-1 !font-[600];
+ @apply !cursor-pointer !inline-flex !flex-1 !items-center !justify-center !gap-1.5;
+ @apply !rounded-md !px-2 !py-1 !text-sm !whitespace-nowrap !transition-colors;
+ @apply focus-visible:!outline-none focus-visible:!ring-2 focus-visible:!ring-yellow-400;
+ @apply focus-visible:!ring-offset-2 disabled:!pointer-events-none disabled:!opacity-50;
+ @apply !shadow-none !border-none !bg-transparent !text-zinc-500 dark:!text-zinc-400;
+ position: relative !important;
+ z-index: 1 !important;
+ background: none !important;
+ border: none !important;
+ box-shadow: none !important;
+ outline: none !important;
+}
+.tabs-container ul li[aria-selected="true"] {
+ @apply !bg-white dark:!bg-zinc-900 !text-zinc-900 dark:!text-white !shadow-sm;
+}
+.tabs-container ul li a:not(.active):hover,
+.tabs-container ul li .tab-trigger:not(.active):hover {
+ @apply !text-zinc-700 dark:!text-zinc-200;
+}
+
+:root {
+ --doc-sidebar-width: 235px !important;
+ --background: 240 10% 3.9%;
+ --foreground: 0 0% 98%;
+ --card: 240 10% 3.9%;
+ --card-foreground: 0 0% 98%;
+ --popover: 240 10% 3.9%;
+ --popover-foreground: 0 0% 98%;
+ --primary: 0 0% 98%;
+ --primary-foreground: 240 5.9% 10%;
+ --secondary: 240 3.7% 15.9%;
+ --secondary-foreground: 0 0% 98%;
+ --muted: 240 3.7% 15.9%;
+ --muted-foreground: 240 5% 64.9%;
+ --accent: 240 3.7% 15.9%;
+ --accent-foreground: 0 0% 98%;
+ --destructive: 0 62.8% 30.6%;
+ --destructive-foreground: 0 85.7% 97.3%;
+ --border: 240 3.7% 15.9%;
+ --input: 240 3.7% 15.9%;
+ --ring: 240 4.9% 83.9%;
+ --chart-1: 220 70% 50%;
+ --chart-2: 160 60% 45%;
+ --chart-3: 30 80% 55%;
+ --chart-4: 280 65% 60%;
+ --chart-5: 340 75% 55%;
+ --sidebar-background: 240 5.9% 10%;
+ --sidebar-foreground: 240 4.8% 95.9%;
+ --sidebar-primary: 224.3 76.3% 48%;
+ --sidebar-primary-foreground: 0 0% 100%;
+ --sidebar-accent: 240 3.7% 15.9%;
+ --sidebar-accent-foreground: 240 4.8% 95.9%;
+ --sidebar-border: 240 3.7% 15.9%;
+ --sidebar-ring: 240 4.9% 83.9%;
+}
+
+/*********************************************************
+* Tokens
+*/
+.namespace {
+ opacity: 0.7;
+}
+
+.token.doctype .token.doctype-tag {
+ color: #569cd6;
+}
+
+.token.doctype .token.name {
+ color: #9cdcfe;
+}
+
+.token.comment,
+.token.prolog {
+ color: #6a9955;
+}
+
+.token.punctuation,
+.language-html .language-css .token.punctuation,
+.language-html .language-javascript .token.punctuation {
+ color: #d4d4d4;
+}
+
+.token.property,
+.token.tag,
+.token.boolean,
+.token.number,
+.token.constant,
+.token.symbol,
+.token.inserted,
+.token.unit {
+ color: #b5cea8;
+}
+
+.token.selector,
+.token.attr-name,
+.token.string,
+.token.char,
+.token.builtin,
+.token.deleted {
+ color: #ce9178;
+}
+
+.language-css .token.string.url {
+ text-decoration: underline;
+}
+
+.token.operator,
+.token.entity {
+ color: #d4d4d4;
+}
+
+.token.operator.arrow {
+ color: #569cd6;
+}
+
+.token.atrule {
+ color: #ce9178;
+}
+
+.token.atrule .token.rule {
+ color: #c586c0;
+}
+
+.token.atrule .token.url {
+ color: #9cdcfe;
+}
+
+.token.atrule .token.url .token.function {
+ color: #dcdcaa;
+}
+
+.token.atrule .token.url .token.punctuation {
+ color: #d4d4d4;
+}
+
+.token.keyword {
+ color: #569cd6;
+}
+
+.token.constructor {
+ color: #569cd6 !important;
+}
+
+.token.keyword.module,
+.token.keyword.control-flow {
+ color: #c586c0;
+}
+
+.token.function,
+.token.function .token.maybe-class-name {
+ color: #dcdcaa;
+}
+
+.token.regex {
+ color: #d16969;
+}
+
+.token.important {
+ color: #569cd6;
+}
+
+.token.italic {
+ font-style: italic;
+}
+
+.token.constant {
+ color: #9cdcfe;
+}
+
+.token.class-name,
+.token.maybe-class-name {
+ color: #4ec9b0;
+}
+
+.token.console {
+ color: #9cdcfe;
+}
+
+.token.parameter {
+ color: #9cdcfe;
+}
+
+.token.interpolation {
+ color: #9cdcfe;
+}
+
+.token.punctuation.interpolation-punctuation {
+ color: #569cd6;
+}
+
+.token.boolean {
+ color: #569cd6;
+}
+
+.token.property,
+.token.variable,
+.token.imports .token.maybe-class-name,
+.token.exports .token.maybe-class-name {
+ color: #9cdcfe;
+}
+
+.token.selector {
+ color: #d7ba7d;
+}
+
+.token.escape {
+ color: #d7ba7d;
+}
+
+.token.tag {
+ color: #569cd6;
+}
+
+.token.class-name.operator {
+ color: #808080;
+}
+
+.token.tag .token.punctuation {
+ color: #808080;
+}
+
+.token.cdata {
+ color: #808080;
+}
+
+.token.attr-name {
+ color: #9cdcfe;
+}
+
+.token.attr-value,
+.token.attr-value .token.punctuation {
+ color: #ce9178;
+}
+
+.token.attr-value .token.punctuation.attr-equals {
+ color: #d4d4d4;
+}
+
+.token.entity {
+ color: #569cd6;
+}
+
+.token.namespace {
+ color: #4ec9b0;
+}
+/*********************************************************
+* Language Specific
+*/
+
+pre[class*="language-javascript"],
+code[class*="language-javascript"],
+pre[class*="language-jsx"],
+code[class*="language-jsx"],
+pre[class*="language-typescript"],
+code[class*="language-typescript"],
+pre[class*="language-tsx"],
+code[class*="language-tsx"] {
+ color: #9cdcfe;
+}
+
+pre[class*="language-css"],
+code[class*="language-css"] {
+ color: #ce9178;
+}
+
+pre[class*="language-html"],
+code[class*="language-html"] {
+ color: #d4d4d4;
+}
+
+.language-regex .token.anchor {
+ color: #dcdcaa;
+}
+
+.language-html .token.punctuation {
+ color: #808080;
+}
+/*********************************************************
+* Line highlighting
+*/
+pre[class*="language-"] > code[class*="language-"] {
+ position: relative;
+ z-index: 1;
+}
+
+.line-highlight.line-highlight {
+ background: #f7ebc6;
+ box-shadow: inset 5px 0 0 #f7d87c;
+ z-index: 0;
+}
+
+/* New feature */
+
+.new-feature {
+ @apply flex items-center dark:bg-yellow-700 bg-yellow-500 px-1.5 py-0 rounded-full ml-1;
+ text-transform: uppercase;
+ font-weight: 800;
+ font-size: 10px;
+ height: 18px;
+}
+
+.new-feature-link svg {
+ display: none;
+}
+
+.navbar__item:hover .new-feature,
+.navbar__link--active .new-feature {
+ @apply dark:bg-yellow-600 bg-yellow-600 !text-white;
+}
+
+/* table */
+
+::root {
+ /* --ifm-table-head-background: */
+}
+
+table:not(.api-docs__table) {
+ @apply !w-full !rounded-md !m-0 !text-sm !caption-bottom;
+}
+
+table:not(.api-docs__table) * {
+ @apply !text-sm;
+}
+
+/* Style table header */
+table:not(.api-docs__table) thead tr {
+ @apply !border-b !border-zinc-400/10; /* Horizontal line below header row */
+}
+
+/* Style table body rows */
+table:not(.api-docs__table) tbody tr {
+ @apply !border-b !border-zinc-400/10 !transition-colors; /* Horizontal line below body rows */
+}
+
+/* Remove border from the last row in the body */
+table:not(.api-docs__table) tbody tr:last-child {
+ @apply !border-0;
+}
+
+/* Style header cells */
+table:not(.api-docs__table) th {
+ @apply !h-12 !px-4 !text-left !align-middle !font-medium !text-zinc-400; /* Adjusted text color */
+}
+
+/* Style data cells */
+table:not(.api-docs__table) td {
+ @apply !p-4 !align-middle;
+}
+
+/* Style table caption */
+table:not(.api-docs__table) caption {
+ @apply !mt-4 !text-sm !text-zinc-500; /* Adjusted text color */
+}
+
+table:not(.api-docs__table) * {
+ @apply !border-t-0 !border-x-0 !border-zinc-400/10;
+}
+
+/* Docgen */
+
+#__docusaurus > div[role="banner"] {
+ @apply min-h-10 !bg-[#1c1c1d] !border-b border-zinc-800 bg-gradient-to-r from-indigo-600 via-purple-600 to-pink-600;
+}
+
+#__docusaurus > div[role="banner"] g {
+ @apply !stroke-white;
+}
+
+.announcement {
+ @apply !text-white font-semibold sm:font-normal text-[0.8rem] sm:text-base px-2 sm:px-4 !py-0 sm:py-2 !my-0;
+}
+
+.announcement a {
+ @apply inline-flex items-center justify-center !text-zinc-100 font-bold bg-yellow-800/50 py-[5px] px-2 sm:py-1 sm:px-3 rounded-md !no-underline text-[0.6rem] sm:text-[0.9rem];
+}
+.announcement a .pro {
+ @apply bg-yellow-500 rounded-md font-bold text-white ml-1 px-1 sm:px-2 sm:py-1.5 py-1 text-[0.5rem] sm:text-[0.7rem];
+ line-height: 1;
+}
+
+.announcement a:hover,
+.announcement a:focus {
+ @apply !text-white bg-yellow-800/80;
+}
+
+.api-docs__section-title {
+ @apply mt-8 mb-4;
+}
+
+.api-docs__section-title h2 {
+ @apply relative mb-12 mt-20 !text-transparent font-extrabold bg-clip-text bg-gradient-to-b from-zinc-800/60 via-zinc-800 to-zinc-800/60 dark:from-zinc-200/60 dark:via-zinc-200 dark:to-zinc-200/60;
+}
+
+/* Underline */
+.api-docs__section-title h2:after {
+ content: "";
+ position: absolute;
+ bottom: -12px;
+ left: 0;
+ width: 100%;
+ height: 4px;
+ background: linear-gradient(to right, #fbbf24, #f59e0b);
+}
+
+.api-docs__section-title:first-child {
+ @apply !mb-3;
+}
+
+.api-docs__definition {
+ @apply !text-sm text-zinc-400 dark:text-zinc-500;
+}
+
+.api-docs__description p {
+ @apply font-medium italic text-lg !bg-clip-text !text-transparent !bg-gradient-to-r from-zinc-800/70 via-zinc-500/80 to-zinc-800/70 dark:from-zinc-200/60 dark:via-zinc-200 dark:to-zinc-200/60;
+}
+
+.api-docs__pre,
+.api-docs__pre > div {
+ @apply !mb-0;
+}
+
+pre {
+ width: 100% !important;
+}
+
+.api-docs__import pre,
+.api-docs__preview pre,
+.api-docs__parameter pre,
+.api-docs__returns > .api-docs__pre pre {
+ @apply !py-0;
+}
+
+.api-docs__import pre * {
+ @apply !text-[0.8rem];
+}
+
+.api-docs__import pre code {
+ @apply py-2.5;
+}
+
+.api-docs__import button {
+ @apply w-6 h-6;
+}
+.api-docs__import svg {
+ @apply !w-3 !h-3 top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2;
+}
+
+.api-docs__icon svg {
+ @apply mr-2 w-4 h-4;
+}
+
+.api-docs__info {
+ @apply text-sm;
+}
+
+.api-docs__info a {
+ @apply !text-blue-400;
+}
+
+.api-docs__preview {
+ @apply mb-4;
+}
+
+.api-docs__tag-text {
+ @apply text-zinc-500 dark:text-zinc-400 mb-3;
+}
+
+.api-docs__parameters {
+ @apply mt-10;
+}
+
+.api-docs__parameter h4 {
+ @apply mb-3 text-xl;
+}
+
+.api-docs__definition svg {
+ @apply dark:invert;
+}
+
+.api-docs__label {
+ @apply text-zinc-500 dark:text-zinc-400;
+}
+
+.api-docs__example-title {
+ @apply mb-3 text-zinc-500 dark:text-zinc-400;
+}
+
+.api-docs__details {
+ @apply flex items-center h-10;
+}
+
+.api-docs__label {
+ @apply w-[100px];
+}
+
+.api-docs__table-wrapper {
+ @apply !w-full max-w-full overflow-x-auto rounded-3xl px-4 pt-2 pb-4 bg-gradient-to-tr from-zinc-100 to-white dark:from-zinc-800 dark:to-zinc-800/25 border dark:border-zinc-800;
+}
+.api-docs__table {
+ display: table;
+ @apply !w-full rounded-md m-0;
+}
+.api-docs__table * {
+ @apply border-t-0 border-x-0 border-zinc-400/10;
+}
+.api-docs__table thead tr {
+ @apply border-0;
+}
+.api-docs__table tr td:last-of-type {
+ @apply w-full;
+}
+.api-docs__table tr th {
+ @apply text-left text-sm uppercase text-zinc-400;
+}
+.api-docs__table tr,
+.api-docs__table thead {
+ @apply !bg-transparent;
+}
+.api-docs__table tr:last-of-type td {
+ @apply border-0;
+}
+.api-docs__table tr > * {
+ @apply !pr-6 py-2;
+}
+
+.api-docs__table-title {
+ @apply text-2xl pt-4 pb-3 px-2 !text-transparent font-extrabold bg-clip-text bg-gradient-to-b from-zinc-800/60 via-zinc-800 to-zinc-800/60 dark:from-zinc-200/60 dark:via-zinc-200 dark:to-zinc-200/60;
+}
+.api-docs__table-name {
+ @apply text-[0.9rem] font-semibold text-zinc-700 dark:text-zinc-200;
+}
+.api-docs__table-description {
+ @apply !text-[0.9rem] font-medium text-zinc-500 dark:text-zinc-400 min-w-[300px];
+}
+
+.api-docs__table pre {
+ overflow-x: auto !important;
+ @apply w-fit rounded-none !py-0 !px-0 !bg-[#232326] mb-0;
+}
+
+.api-docs_table .codeBlock {
+ @apply md:max-w-[300px] lg:max-w-[400px];
+}
+
+.api-docs__table pre code {
+ @apply !py-2 !px-2;
+ max-width: 270px;
+}
+.api-docs__table pre * {
+ @apply !text-[0.7rem];
+}
+
+/* Playground */
+
+.live-code-block .toaster {
+ position: absolute !important;
+}
+.live-code-block .toaster [data-sonner-toast][data-styled="true"] [data-content],
+.live-code-block .toaster [data-sonner-toast][data-styled="true"] [data-title] {
+ @apply w-full;
+}
+
+.live-code-block {
+ @apply mt-4 mb-6;
+}
+
+.live-code-block-size-lg .api-playground__editor-wrapper,
+.live-code-block-size-lg .api-playground,
+.live-code-block-size-lg .api_playground_wrapper {
+ @apply min-h-[700px] max-h-[700px];
+}
+
+.live-code-block-size-md .api-playground__editor-wrapper,
+.live-code-block-size-md .api-playground,
+.live-code-block-size-md .api_playground_wrapper {
+ @apply min-h-[500px] max-h-[500px];
+}
+.live-code-block-size-sm .api-playground__editor-wrapper,
+.live-code-block-size-sm .api-playground,
+.live-code-block-size-sm .api_playground_wrapper {
+ @apply min-h-[325px] max-h-[325px];
+}
+
+.api_playground_wrapper > svg {
+ @apply h-full;
+}
+
+.api-playground__run-example {
+ @apply h-full;
+}
+
+.api-playground__header {
+ @apply flex items-center py-2 pr-4 pl-3 text-gray-400 justify-between border-b;
+ @apply dark:bg-gradient-to-br dark:from-zinc-900 dark:to-zinc-800 dark:border-zinc-700 dark:text-zinc-100;
+}
+
+.api_playground_wrapper {
+ @apply relative;
+}
+
+.api-playground {
+ @apply h-full relative;
+}
+
+.api-playground__preview {
+ @apply w-full h-full p-4;
+}
+
+.api-playground__preview:not(.api-playground__preview--log) > * {
+ @apply bg-zinc-700 rounded-md shadow-md p-4;
+}
+
+.api-playground__label {
+ @apply flex items-center bg-[#1c1c1d] px-4 py-2 mt-4 rounded-t-lg text-sm uppercase font-bold border-b border-zinc-500/30;
+}
+.api-playground__indicator {
+ @apply flex w-2 h-2 me-3 bg-red-500 rounded-full ml-2;
+}
+.api-playground__error {
+ @apply absolute bottom-0 left-0 right-0;
+ @apply rounded-none bg-red-500 dark:bg-red-700 bg-opacity-30 dark:bg-opacity-40 text-red-700 dark:text-red-200;
+ @apply p-4 text-sm;
+}
+.api-playground__editor-wrapper {
+ @apply overflow-y-auto translate-y-[-1px] xl:rounded-bl-md h-full;
+}
+.api-playground__editor-wrapper > div:first-child {
+ @apply z-10 sticky !h-0 flex items-center justify-end;
+}
+.api-playground__editor-wrapper:hover button {
+ @apply !opacity-100;
+}
+.api-playground__editor {
+ @apply bg-[#1c1c1d] border border-transparent h-full !overflow-y-auto;
+}
+.api-playground__editor * {
+ @apply !text-sm;
+}
+button.api-playground__more {
+ @apply absolute bottom-1 left-1/2 -translate-x-1/2 z-10 text-white font-semibold bg-yellow-400 hover:bg-yellow-500 focus:outline-none focus:ring-4 focus:ring-blue-300 rounded-full text-sm px-3 py-1 text-center me-2 mb-2 dark:focus:ring-blue-900;
+}
+
+.api-playground__show-less {
+ @apply max-h-[80px];
+}
+
+.api-playground__show-more {
+ @apply !pb-6;
+}
+
+.api-playground__switch {
+ @apply flex-col;
+}
+.api-playground__switch .api-playground__editor {
+ @apply !rounded-t-2xl;
+}
+.api-playground__backdrop {
+ @apply absolute bottom-0 h-20 z-[1] w-full bg-gradient-to-t from-20% from-[#1c1c1d] to-transparent;
+}
+
+.api-playground__controls {
+ @apply flex gap-2 justify-start;
+}
+.api-playground__header {
+ @apply border-b border-zinc-500/30;
+}
+
+.api-playground__log-row * {
+ @apply text-xs;
+}
+.api-playground__log-row {
+ @apply !bg-[#1f1f20] border-t border-zinc-500/30;
+}
+.api-playground__log-row:nth-child(2n + 1) {
+ @apply !bg-[#1e1e1f];
+}
+.api-playground__log-row:last-child {
+ @apply !border-b border-zinc-500/30;
+}
+.api-playground__log-row pre {
+ @apply p-2 bg-transparent;
+}
+.api-playground__preview.api-playground__preview--log {
+ @apply !pb-0;
+}
+
+.api-playground__content {
+ max-height: calc(100% - 51px);
+ @apply overflow-y-auto rounded-b-md xl:rounded-b-none xl:rounded-br-md;
+}
+
+.api-playground__preview--log {
+ @apply p-0 !pb-4 w-[calc(100%-4px)] ml-[2px] xl:w-[calc(100%-2px)] xl:ml-0;
+}
+.api-playground__log-row__index div {
+ @apply flex items-center justify-center w-6 h-6 mt-1 mb-1 ml-2;
+}
+.api-playground__no-logs {
+ @apply !text-zinc-400/70;
+}
+
+/* Main */
+
+.shiny-btn {
+ border: 1px solid transparent !important;
+ @apply relative text-zinc-600 dark:text-zinc-300 hover:text-black dark:hover:text-white transition-all duration-150 ease-in-out [background:linear-gradient(theme(colors.zinc.100),_theme(colors.zinc.50))_padding-box,_conic-gradient(theme(colors.zinc.400),_theme(colors.zinc.200)_25%,_theme(colors.zinc.200)_75%,_theme(colors.zinc.400)_100%)_border-box!important] dark:[background:linear-gradient(theme(colors.zinc.700),_theme(colors.zinc.800))_padding-box,_conic-gradient(theme(colors.zinc.400),_theme(colors.zinc.700)_25%,_theme(colors.zinc.700)_75%,_theme(colors.zinc.400)_100%)_border-box!important] before:absolute before:inset-0 before:bg-white/30 dark:before:bg-zinc-700/30 before:pointer-events-none before:z-[-1];
+}
+
+.shiny-btn {
+ @apply rounded-xl before:!rounded-sm;
+}
+
+.shiny-btn::before {
+ @apply rounded-xl hidden;
+}
+
+.shiny-btn:hover {
+ @apply dark:brightness-110 shadow-yellow-500/40 dark:shadow-yellow-500/40 shadow-[inset_0_0_4px_rgba(0,0,0,0.6)];
+}
+
+.shiny-label {
+ font-size: 14px;
+ @apply text-yellow-600 dark:text-white border relative inline-flex items-center pb-[2px] pl-2.5 pr-2 rounded-full gap-x-2 border-yellow-400/50 dark:border-yellow-500/30 bg-yellow-400/10 dark:bg-yellow-500/10 before:scale-y-110 before:absolute before:inset-x-4 before:-bottom-px before:bg-gradient-to-r before:from-transparent before:via-yellow-500 dark:before:via-yellow-50 before:to-transparent before:h-px before:w-3/5;
+}
+
+.shadow-neon {
+ box-shadow:
+ 0px 0px var(--tw-shadow-color),
+ 0px 0px 4px #fff,
+ 0px 0px 8px var(--tw-shadow-color),
+ 0px 0px 16px var(--tw-shadow-color);
+}
+
+body:not(.dark) .title,
+body:not(.dark) .api-docs__section-title,
+body:not(.dark) .title * {
+ text-shadow:
+ -1px -1px 0 hsla(0, 0%, 0%, 0.1),
+ 1px 1px 0 rgba(200, 200, 200, 0.1);
+}
+body.dark .title,
+body.dark .api-docs__section-title,
+body.dark .title * {
+ text-shadow:
+ -1px -1px 0 hsla(0, 0%, 100%, 0.2),
+ 1px 1px 0 rgba(0, 0, 0, 0.1);
+}
+
+/* Playground */
+
+.playground .editor > pre > pre {
+ padding: 0 !important;
+}
+
+/**
+ * Mermaid
+ */
+
+.docusaurus-mermaid-container .edge {
+ opacity: 0.2;
+}
+
+/**
+ * Docs page
+ */
+
+main > div.container {
+ @apply !pt-0;
+}
+
+main .col:not(.col--3):not(.toc):not(.table-of-contents) ol,
+main .col:not(.col--3):not(.toc):not(.table-of-contents) ul {
+ margin-top: 10px;
+ padding-left: 30px;
+}
+
+main .col:not(.col--3) ol:not(.toc):not(.toaster):not(.table-of-contents) li {
+ @apply relative mb-4 pl-3 text-lg;
+ list-style: decimal;
+}
+
+main .col:not(.col--3) ol:not(.toc):not(.toaster):not(.table-of-contents) > li::before {
+ @apply absolute left-[-24px] top-[2px] w-[28px] h-[28px] rounded-full z-[-1] bg-zinc-200 dark:bg-zinc-700;
+ content: "";
+}
+main .col:not(.col--3) ol:not(.toc):not(.toaster):not(.table-of-contents) li::marker {
+ @apply text-zinc-200 dark:text-zinc-400 text-sm;
+}
+
+/* h1 */
+main .col:not(.col--3) ol:not(.toc):not(.toaster):not(.table-of-contents) li:has(> h1:first-child)::marker {
+ @apply text-3xl;
+}
+/* h2 */
+main .col:not(.col--3) ol:not(.toc):not(.toaster):not(.table-of-contents) > li:has(> h2:first-child)::before {
+ @apply absolute left-[-36px] top-[10px] w-[40px] h-[40px] rounded-full z-[-1] bg-zinc-200 dark:bg-zinc-700;
+ content: "";
+}
+main .col:not(.col--3) ol:not(.toc):not(.toaster):not(.table-of-contents) li:has(> h2:first-child)::marker {
+ @apply text-2xl;
+}
+main .col:not(.col--3) ol:not(.toc):not(.toaster):not(.table-of-contents) li > h2:first-child {
+ @apply translate-y-[3px];
+}
+/* h3 */
+main .col:not(.col--3) ol:not(.toc):not(.toaster):not(.table-of-contents) > li:has(> h3:first-child)::before {
+ @apply absolute left-[-31px] top-[1px] w-[35px] h-[35px] rounded-full z-[-1] bg-zinc-200 dark:bg-zinc-700;
+ content: "";
+}
+main .col:not(.col--3) ol:not(.toc):not(.toaster):not(.table-of-contents) li:has(> h3:first-child)::marker {
+ @apply text-xl;
+}
+main .col:not(.col--3) ol:not(.toc):not(.toaster):not(.table-of-contents) li > h3:first-child {
+ @apply translate-y-[2px];
+}
+
+/* h4 */
+main .col:not(.col--3) ol:not(.toc):not(.toaster):not(.table-of-contents) > li:has(> h4:first-child)::before {
+ @apply absolute left-[-27px] top-[0px] w-[30px] h-[30px] rounded-full z-[-1] bg-zinc-200 dark:bg-zinc-700;
+ content: "";
+}
+main .col:not(.col--3) ol:not(.toc):not(.toaster):not(.table-of-contents) li:has(> h4:first-child)::marker {
+ @apply text-lg;
+}
+/* h5 */
+
+main .col:not(.col--3) ol:not(.toc):not(.toaster):not(.table-of-contents) > li:has(> h5:first-child)::before {
+ @apply absolute left-[-25px] top-[0px] w-[28px] h-[28px] rounded-full z-[-1] bg-zinc-200 dark:bg-zinc-700;
+ content: "";
+}
+main .col:not(.col--3) ol:not(.toc):not(.toaster):not(.table-of-contents) li:has(> h5:first-child)::marker {
+ @apply text-base;
+}
+/* h6 */
+main .col:not(.col--3) ol:not(.toc):not(.toaster):not(.table-of-contents) > li:has(> h6:first-child)::before {
+ @apply absolute left-[-23px] top-[-1px] w-[26px] h-[26px] rounded-full z-[-1] bg-zinc-200 dark:bg-zinc-700;
+ content: "";
+}
+main .col:not(.col--3) ol:not(.toc):not(.toaster):not(.table-of-contents) li:has(> h6:first-child)::marker {
+ @apply text-sm;
+}
+
+/* else */
+main .col:not(.col--3) ul:not(.toc):not(.toaster):not(.table-of-contents) li {
+ list-style: initial;
+}
+
+main .col:not(.col--3) ul li,
+main .col:not(.col--3) ol li {
+ padding-left: 5px;
+}
+
+.theme-doc-toc-mobile {
+ @apply hidden;
+}
+
+.theme-doc-toc-mobile .table-of-contents {
+ @apply border-zinc-300 dark:border-zinc-800;
+}
+
+main blockquote {
+ @apply border-l-0 pl-0 mt-8;
+}
+.docs-wrapper main blockquote > p {
+ line-height: 1.7 !important;
+ @apply font-medium italic text-xl bg-clip-text text-transparent bg-gradient-to-r from-zinc-800/70 via-zinc-500/80 to-zinc-800/70;
+}
+.docs-wrapper .dark main blockquote > p {
+ @apply from-zinc-200/90 via-zinc-50 to-zinc-200/80;
+}
+
+body .col .nav-tabs li {
+ list-style: none !important;
+}
+
+.nav-tabs ~ div.markdown header h1 {
+ display: none;
+}
+
+.theme-doc-sidebar-container > div {
+ position: sticky;
+ top: 90px;
+ margin-top: 60px;
+ height: 100%;
+ max-height: calc(100vh - 100px);
+ overflow-y: auto;
+ overflow-x: hidden;
+}
+
+.theme-doc-footer-edit-meta-row a,
+.theme-edit-this-page {
+ display: flex;
+ align-items: center;
+}
+
+hr {
+ @apply w-full h-[1px] opacity-60 dark:opacity-20 my-8;
+}
+
+p,
+span,
+div {
+ @apply text-zinc-700 dark:text-zinc-300;
+ font-size: 17px;
+ font-weight: 500;
+}
+
+b,
+strong {
+ @apply text-zinc-800 dark:text-zinc-100;
+}
+
+strong {
+ @apply font-bold;
+}
+
+.docs-wrapper h1 {
+ @apply !mb-0;
+}
+
+.docs-wrapper p {
+ @apply my-4 text-[17px];
+ line-height: 1.8;
+}
+
+.docs-wrapper table p {
+ @apply my-0;
+}
+
+.docs-wrapper table:not(.api-docs__table) {
+ display: table !important;
+ @apply w-full rounded-3xl pt-2 bg-gradient-to-tr from-zinc-100 to-white dark:from-zinc-800 dark:to-zinc-800/25 border dark:border-zinc-800 overflow-hidden;
+}
+.docs-wrapper table:not(.api-docs__table) thead {
+ @apply bg-transparent;
+}
+.docs-wrapper table:not(.api-docs__table) tbody tr:nth-child(2n) {
+ @apply bg-zinc-600/10;
+}
+.docs-wrapper table:not(.api-docs__table) tbody tr:last-child td {
+ @apply border-b-0;
+}
+
+main a > span,
+main a > div,
+main a > p,
+main a {
+ @apply text-[rgb(164,120,8)] dark:text-[rgb(202,160,20)] decoration-[rgb(164,125,8)] dark:decoration-[rgb(202,156,20)];
+}
+
+.avatar__name * {
+ @apply !font-bold;
+}
+
+body .theme-code-block {
+ @apply border-[1px] border-zinc-700/20 dark:border-transparent relative text-zinc-300 hover:text-white transition-all duration-150 ease-in-out [background:linear-gradient(theme(colors.zinc.700),_theme(colors.zinc.800))_padding-box,_conic-gradient(theme(colors.zinc.400),_theme(colors.zinc.700)_25%,_theme(colors.zinc.700)_75%,_theme(colors.zinc.400)_100%)_border-box!important] before:absolute before:inset-0 before:bg-zinc-700/30 before:pointer-events-none before:z-[-1];
+}
+
+body .theme-code-block span {
+ @apply text-sm;
+}
+
+.theme-code-block > div:first-child:not(:last-child) {
+ @apply flex items-center text-gray-400 justify-between;
+ @apply dark:bg-gradient-to-br dark:from-zinc-900 dark:to-zinc-800 dark:border-zinc-700 dark:text-zinc-100;
+ @apply !text-[rgba(255,255,255,0.7)] text-[0.9rem] font-semibold border-zinc-400/10;
+ @apply relative text-zinc-300 hover:text-white;
+ @apply before:absolute before:inset-0 before:bg-zinc-700/30 before:pointer-events-none before:z-[-1] transition-all duration-150 ease-in-out;
+ @apply rounded-none py-2;
+}
+
+.theme-code-block > div:first-child::before {
+ @apply mr-2;
+ content: "➥";
+}
+
+.clean-btn[title="Copy"] svg * {
+ @apply !fill-white;
+}
+
+.prism-code {
+ @apply rounded-none !py-4 !px-0 !bg-[#1c1c1d];
+}
+
+.theme-code-block-highlighted-line {
+ @apply !bg-zinc-700/30;
+}
+
+.code-block-code-editor-split {
+ display: flex;
+ height: 20px; /* control the size */
+ background:
+ conic-gradient(from 135deg at top, #2a2a2a 90deg, #0000 0) top,
+ conic-gradient(from 135deg at top, #0000 90deg, #2a2a2a 0) bottom;
+ background-size: 15px 50%;
+ background-repeat: repeat-x;
+ @apply -mx-4 mb-4;
+}
+
+.token {
+ color: white;
+}
+
+.theme-code-block > div:last-child::before {
+ display: none;
+}
+
+body .theme-code-block {
+ @apply !rounded-lg overflow-hidden;
+}
+
+*:not(pre) > code {
+ @apply pt-[3px] pb-[2px] px-1.5 text-[0.8em] text-white bg-zinc-600/60 !border-0 !border-b-2 border-zinc-500/30;
+}
+
+.docs-wrapper a:has(> code) {
+ @apply !no-underline;
+}
+
+.docs-wrapper a:not(.table-of-contents__link) > code {
+ @apply bg-yellow-500/60 border-yellow-400/30 hover:bg-yellow-400/60 hover:border-yellow-300/50;
+}
+
+a.table-of-contents__link > code {
+ @apply !text-white;
+}
+
+pre[class*="language-"] {
+ margin: 0 !important;
+ padding-top: 0 !important;
+ padding-bottom: 0 !important;
+}
+
+pre[class*="language-"] > code {
+ @apply bg-[#171717];
+}
+
+.code-block-diff-add-line {
+ @apply bg-green-400/20;
+ display: block;
+ margin: 0 -40px;
+ padding: 0 40px;
+}
+
+.code-block-diff-add-line::before {
+ position: absolute;
+ left: 8px;
+ padding-right: 8px;
+ content: "+";
+}
+
+.code-block-diff-remove-line {
+ @apply bg-red-400/20;
+ display: block;
+ margin: 0 -40px;
+ padding: 0 40px;
+}
+
+.code-block-diff-remove-line::before {
+ position: absolute;
+ left: 8px;
+ padding-right: 8px;
+ content: "-";
+}
+
+.code-block-error-line {
+ @apply bg-red-400/20;
+ display: block;
+ margin: 0 -40px;
+ padding: 0 40px;
+}
+
+/**
+ * use magic comments to mark diff blocks
+ */
+pre code:has(.code-block-diff-add-line) {
+ padding-left: 40px !important;
+}
+
+pre code:has(.code-block-diff-remove-line) {
+ padding-left: 40px !important;
+}
+
+/* Alerts */
+
+.alert *:not(pre) > code {
+ @apply bg-zinc-400/20 border-zinc-600/5 dark:bg-zinc-50/10 dark:border-zinc-50/5 border;
+}
+
+.alert {
+ @apply relative px-6 md:px-8 py-8 rounded-2xl mt-6 border-0 overflow-hidden;
+}
+.alert::before {
+ background-image: url("/img/noise.webp");
+ background-size: contain;
+ background-position: center;
+ background-repeat: repeat;
+ content: "";
+ @apply absolute inset-0 -z-10 opacity-[0.05] pointer-events-none;
+}
+.alert::after {
+ @apply inset-0 absolute [background-image:radial-gradient(88%_100%_at_top,rgba(255,255,255,0.5),rgba(255,255,255,0))] z-[1] opacity-30 pointer-events-none;
+}
+.alert > div:first-child {
+ line-height: 1.9;
+ @apply mb-3 text-2xl capitalize font-extrabold flex items-center gap-2;
+}
+.alert > div:first-child svg {
+ @apply -mt-1 -mr-2 w-8 h-8;
+}
+.alert > div:last-child > ul,
+.alert > div:last-child > ol {
+ @apply -ml-1;
+}
+.alert > div:last-child > p {
+ @apply px-2;
+}
+.alert > div:last-child b,
+.alert > div:last-child strong {
+ @apply !text-white;
+}
+
+.alert--learn {
+ border: 1px solid;
+ @apply bg-zinc-200 dark:bg-zinc-600/40 text-[#ebecf0] !border-zinc-500/60;
+}
+.alert--learn > div:first-child {
+ @apply text-[#f6f7f9];
+}
+.alert--learn > div:first-child svg {
+ @apply stroke-[#f6f7f9] fill-transparent;
+}
+.alert--learn > div:last-child > * {
+ @apply text-white text-opacity-80;
+}
+
+.alert--secondary {
+ @apply bg-teal-200 dark:bg-teal-900 bg-opacity-20 dark:bg-opacity-30;
+}
+.alert--secondary > div:first-child {
+ @apply text-teal-600 dark:text-teal-500;
+}
+.alert--secondary > div:first-child svg {
+ @apply stroke-teal-600 dark:stroke-teal-500 fill-transparent;
+}
+.alert--secondary > div:last-child > * {
+ @apply text-teal-50 text-opacity-80;
+}
+.alert--secondary > div:last-child a {
+ @apply text-teal-400 decoration-teal-400 text-opacity-80;
+}
+
+.alert--tip {
+ @apply bg-green-200 dark:bg-green-700 bg-opacity-40 dark:bg-opacity-40;
+}
+.alert--tip > div:first-child {
+ @apply text-green-600 dark:text-green-400;
+}
+.alert--tip > div:first-child svg {
+ @apply stroke-green-600 dark:stroke-green-400 fill-transparent;
+}
+.alert--tip > div:last-child > * {
+ @apply text-green-50 text-opacity-80;
+}
+.alert--tip > div:last-child a {
+ @apply text-green-400 decoration-green-400 text-opacity-80;
+}
+
+.alert--success {
+ @apply bg-cyan-200 dark:bg-cyan-700 bg-opacity-40 dark:bg-opacity-40;
+}
+.alert--success > div:first-child {
+ @apply text-amber-600 dark:text-amber-400;
+}
+.alert--success > div:first-child svg {
+ @apply stroke-amber-600 dark:stroke-amber-400 fill-transparent;
+}
+.alert--success > div:last-child > * {
+ @apply text-amber-100;
+}
+.alert--success > div:last-child a {
+ @apply text-cyan-400 decoration-cyan-400 text-opacity-80;
+}
+
+.alert--info {
+ @apply bg-blue-300 dark:bg-blue-700 bg-opacity-30 dark:bg-opacity-30;
+}
+.alert--info > div:first-child {
+ @apply text-blue-600 dark:text-blue-500;
+}
+.alert--info > div:first-child svg {
+ @apply stroke-blue-600 dark:stroke-blue-500 fill-transparent;
+}
+.alert--info > div:last-child > * {
+ @apply text-blue-50 text-opacity-80;
+}
+.alert--info > div:last-child a {
+ @apply text-blue-400 decoration-blue-400 text-opacity-80;
+}
+.alert--info::before {
+ @apply opacity-[0.025];
+}
+
+.alert--warning {
+ @apply bg-yellow-400 dark:bg-yellow-700 bg-opacity-40 dark:bg-opacity-40;
+}
+.alert--warning > div:first-child {
+ @apply text-yellow-600 dark:text-yellow-400;
+}
+.alert--warning > div:first-child svg {
+ @apply stroke-yellow-600 dark:stroke-yellow-400 fill-transparent;
+}
+.alert--warning > div:last-child > * {
+ @apply text-yellow-50 text-opacity-70;
+}
+.alert--warning > div:last-child a {
+ @apply text-yellow-400 decoration-yellow-400 text-opacity-80;
+}
+
+.alert--caution {
+ @apply bg-yellow-400 dark:bg-yellow-700 bg-opacity-40 dark:bg-opacity-40;
+}
+.alert--caution > div:first-child {
+ @apply text-yellow-600 dark:text-yellow-400;
+}
+.alert--caution > div:first-child svg {
+ @apply stroke-yellow-600 dark:stroke-yellow-400 fill-transparent;
+}
+.alert--caution > div:last-child > * {
+ @apply text-yellow-50 text-opacity-80;
+}
+.alert--caution > div:last-child a {
+ @apply text-yellow-400 decoration-yellow-400 text-opacity-80;
+}
+
+.alert--danger {
+ @apply bg-red-500 dark:bg-red-700 bg-opacity-30 dark:bg-opacity-40;
+}
+.alert--danger > div:first-child {
+ @apply text-red-600 dark:text-red-300;
+}
+.alert--danger > div:first-child svg {
+ @apply stroke-red-600 dark:stroke-red-300 fill-transparent;
+}
+.alert--danger > div:last-child > * {
+ @apply text-red-50 text-opacity-80;
+}
+.alert--danger > div:last-child a {
+ @apply text-red-400 decoration-red-400 text-opacity-80;
+}
+
+/* Blog */
+
+article {
+ @apply relative;
+}
+
+article .markdown p:first-of-type img {
+ @apply bg-gradient-to-br from-transparent via-zinc-300/20 to-transparent rounded-3xl p-px mb-8;
+}
+
+article header h2 a {
+ @apply pb-6 text-3xl sm:text-4xl font-extrabold text-black dark:text-white;
+}
+
+.avatar__photo {
+ @apply w-10 h-10;
+}
+
+.avatar__name a span {
+ @apply !font-extrabold;
+}
+
+.avatar__subtitle {
+ @apply text-xs;
+}
+
+aside nav h3 {
+ @apply text-lg font-extrabold;
+}
+
+.avatar__name span {
+ @apply text-yellow-500;
+}
+
/**
* Any CSS included here will be global. The classic template
* bundles Infima by default. Infima is a CSS framework designed to
@@ -5,551 +1335,1035 @@
*/
/* You can override the default Infima variables here. */
-@import url("https://fonts.googleapis.com/css2?family=Barlow:wght@100;200;300;400;500;600;700;800;900&display=swap");
+:root {
+ --ifm-color-primary: rgb(255, 213, 0);
+ --ifm-color-primary-dark: rgb(229, 188, 0);
+ --ifm-color-primary-darker: rgb(204, 163, 0);
+ --ifm-color-primary-darkest: rgb(153, 119, 0);
+ --ifm-color-primary-light: rgb(255, 229, 51);
+ --ifm-color-primary-lighter: rgb(255, 244, 105);
+ --ifm-color-primary-lightest: rgb(255, 252, 141);
+ --ifm-code-font-size: 95%;
+ --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.1);
+ --ifm-navbar-background-color: transparent;
+}
+
+/* For readability concerns, you should choose a lighter palette in dark mode. */
+[data-theme="dark"] {
+ --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3);
+ --ifm-navbar-background-color: transparent;
+}
+
+html {
+ background: transparent !important;
+ background-color: transparent !important;
+ font-family: Figtree;
+}
+
+.footer {
+ background-color: transparent;
+}
+
+html[data-theme="light"] {
+ --text-primary: #fff;
+ --text-secondary: #1c1c1d;
+ --background: var(--text-secondary);
+ --ifm-background-color: var(--text-secondary);
+}
html[data-theme="dark"] {
- --ifm-color-primary: rgb(227, 187, 46); /* Links */
- --ifm-color-primary-dark: rgb(232 188 65); /* Hover */
- --ifm-color-primary-darker: rgb(229, 173, 65);
- --ifm-color-primary-darkest: rgb(212, 155, 41);
- --ifm-color-primary-light: rgb(255, 225, 75);
- --ifm-color-primary-lighter: rgb(255, 237, 145);
- --ifm-color-primary-lightest: rgb(255, 242, 180);
- --ifm-code-font-size: 95%;
- --shadow-color: rgba(232, 188, 65, 0.1);
+ --text-primary: rgb(255, 255, 255);
+ --text-secondary: #e7e6e6;
+ --background: #1c1c1d;
+ --ifm-background-color: var(--text-secondary);
+}
+
+body {
+ margin: 0;
+ padding: 0;
+ color: var(--text-primary);
+ font-family: Figtree;
+ background: var(--background);
+}
+
+.navbar {
+ box-shadow: none;
+ border: 0;
+ background: transparent !important;
+}
+
+@media (min-width: 996px) {
+ .navbar {
+ @apply backdrop-blur-sm;
+ box-shadow: none;
+ border: 0;
+ background: transparent !important;
+ }
+
+ .docs_sidebar {
+ }
+
+ .docs-wrapper .main-wrapper {
+ @apply px-6;
+ }
+
+ .navbar--fixed-top {
+ @apply py-6 px-10 h-auto;
+ }
+
+ .nav-tabs + div:not(.markdown) {
+ display: none !important;
+ }
+ .navbar__link {
+ @apply flex;
+ }
+}
+@media (max-width: 997px) {
+ .navbar {
+ background: var(--background) !important;
+ }
+ .navbar-sidebar {
+ background: var(--background) !important;
+ }
+ .navbar__items {
+ flex-direction: row-reverse;
+ }
+ .navbar__items .navbar__brand {
+ margin-right: auto;
+ }
+ body .navbar__items--right > div > button.DocSearch-Button {
+ @apply !px-2;
+ }
+ body .navbar__items--right > div:last-child {
+ margin-right: 50px !important;
+ }
+ .row.footer__links {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ }
+}
+@media (max-width: 500px) {
+ .footer__item {
+ @apply text-sm;
+ }
+}
+/* Github icon */
+
+.github {
+ padding: var(--ifm-navbar-item-padding-vertical);
+}
+
+.github::before {
+ display: block;
+ background-image: url("/img/github.svg");
+ background-size: contain;
+ content: "";
+ width: 24px;
+ height: 24px;
+}
+
+.github svg {
+ display: none;
+}
+
+.github:hover {
+ opacity: 0.7;
+}
+
+html[data-theme="dark"] .github::before {
+ filter: invert(100%);
+}
+
+html[data-theme="dark"] .navbar-sidebar .github {
+ filter: invert(0%);
+ padding: var(--ifm-menu-link-padding-vertical) var(--ifm-menu-link-padding-horizontal);
+}
+
+.navbar-sidebar .github::before {
+ width: 18px;
+ height: 18px;
+}
+
+.navbar-sidebar .github {
+ display: flex;
+ gap: 5px;
+}
- --docsearch-muted-color: var(--ifm-color-emphasis-700) !important;
- --docsearch-footer-shadow: inset 0 1px 0 0 rgba(204, 168, 2, 0.5), 0 -4px 8px 0 rgba(0, 0, 0, 0.2) !important;
- --docsearch-modal-shadow: inset 1px 1px 0 0 #0003093b, 0 3px 8px 0 #000309 !important;
+.navbar-sidebar--show .github {
+ padding: var(--ifm-menu-link-padding-vertical) var(--ifm-menu-link-padding-horizontal);
}
-html[data-theme="light"] {
- --ifm-color-primary: rgb(216 173 12); /* Links */
- --ifm-color-primary-dark: rgb(232 188 65); /* Hover */
- --ifm-color-primary-darker: rgb(229, 173, 65);
- --ifm-color-primary-darkest: rgb(212, 155, 41);
- --ifm-color-primary-light: rgb(255, 225, 75);
- --ifm-color-primary-lighter: rgb(255, 237, 145);
- --ifm-color-primary-lightest: rgb(255, 242, 180);
- --ifm-code-font-size: 95%;
- --shadow-color: rgba(232, 188, 65, 0.2);
+.navbar__inner .github {
+ @apply !ml-3;
+ font-size: 0 !important;
}
-html[data-theme="dark"] {
- --ifm-footer-background-color: #0c0d0e;
- --section-background: var(--ifm-background-surface-color);
+.navbar__items--right {
+ @apply space-x-2;
+}
+.navbar__link {
+ @apply items-center font-medium text-sm text-zinc-500 hover:!text-zinc-800 dark:text-zinc-400 dark:hover:!text-white transition duration-150 ease-in-out;
+}
+.navbar__link.navbar__link--active {
+ @apply text-zinc-900 dark:text-white;
}
-html[data-theme="light"] {
- --ifm-background-color: #fff;
- --section-background: #e9e9e9;
+.nav_versioning {
+ @apply px-2 h-[34px] border border-zinc-800 bg-zinc-900/80 rounded-md;
}
-html {
- font-family: "Barlow", sans-serif;
- font-weight: 500;
- font-size: 1.1rem;
+/* .nav_versioning {
+ @apply font-bold text-opacity-80;
}
-b {
- font-weight: 700;
- color: #7e9cff;
+.nav_versioning::after {
+ content: " →";
+ color: var(--ifm-color-primary);
+ margin-left: 5px;
+} */
+
+.navbar__items--right {
+ @apply !gap-0;
}
-strong {
- font-weight: 800;
- color: #7e9cff;
+@media (max-width: 997px) {
+ .navbar--fixed-top .navbar__items--right button {
+ @apply hidden;
+ }
}
-code {
- color: #7e9cff;
+.navbar__toggle {
+ @apply scale-150;
}
-.docusaurus-highlight-code-line {
- background-color: rgba(0, 0, 0, 0.1);
- display: block;
- margin: 0 calc(-1 * var(--ifm-pre-padding));
- padding: 0 var(--ifm-pre-padding);
+.navbar__items--right > * {
+ @apply !m-0;
}
-html[data-theme="dark"] .docusaurus-highlight-code-line {
- background-color: rgba(0, 0, 0, 0.3);
+.navbar__logo:hover {
+ opacity: 0.7;
}
-html[data-theme="light"] .alert--secondary {
- background: #f7f7f7;
+.navbar__items > div {
+ margin-left: 10px !important;
}
-html[data-theme="light"] .main-wrapper {
- background-image: radial-gradient(var(--ifm-color-emphasis-300) 1px, transparent 1px),
- radial-gradient(var(--ifm-color-emphasis-300) 1px, transparent 1px);
- background-position: 0 0, 50px 50px;
- background-size: 100px 100px;
+.navbar__items .navbar__link {
+ @apply px-4;
+ font-weight: 600;
+ font-size: 15px;
}
-html[data-theme="dark"] .main-wrapper {
- background-image: radial-gradient(rgba(255, 255, 255, 0.1) 1px, transparent 1px),
- radial-gradient(rgba(255, 255, 255, 0.1) 1px, transparent 1px);
- background-position: 0 0, 50px 50px;
- background-size: 100px 100px;
+.navbar__items a:nth-child(3) {
+ @apply ml-10;
}
-.pagination-nav__link {
- background: var(--ifm-background-color);
+.menu__list {
+ @apply !pl-2;
}
-.navbar__item {
- font-weight: 700;
+.menu__list-item-collapsible {
+ @apply !bg-transparent mt-5 !text-inherit !cursor-pointer;
+}
+.menu__list-item-collapsible .menu__link {
+ @apply text-xs uppercase !text-inherit font-bold tracking-wider !cursor-pointer;
}
-.menu__link--active {
+.menu__link {
+ padding-top: 10px;
+ padding-bottom: 10px;
font-weight: 600;
+ font-size: 14px;
+}
+.custom-sidebar-menu a.menu__link--active {
+ color: inherit !important;
+}
+.menu__link--active:not(.menu__link--sublist) {
+ @apply dark:bg-zinc-800 bg-zinc-300/40;
}
-html[data-theme="light"] .menu__link--active {
- text-shadow: 0px 0px 9px rgba(255, 255, 255, 1);
+.menu__list-item > .menu__link {
+ @apply hover:dark:text-white hover:text-zinc-900;
}
-@media (max-width: 996px) {
- .menu__link {
- padding: 10px var(--ifm-menu-link-padding-horizontal);
- font-size: 1.1rem;
- }
- .navbar-sidebar__back {
- padding: 0.7rem 1.5rem;
- font-size: 1.1rem;
- }
+.menu__list-item > .menu__link {
+ @apply active:dark:bg-zinc-700 active:bg-zinc-200 dark:active:text-zinc-300 active:text-zinc-700;
}
-/* Announcement */
+.navbar .clean-btn {
+ @apply shiny-btn;
+ position: relative;
+ line-height: 1;
+}
-#__docusaurus > div[role="region"] {
- background: var(--ifm-color-primary-dark);
+.clean-btn {
+ @apply w-[24px] h-[24px] !p-[0.3rem];
}
-/* Headings */
+.clean-btn svg {
+ @apply w-full h-full;
+}
-.page-section-title {
- position: relative;
- text-align: center;
- font-size: 2.3rem;
- font-weight: 800;
- max-width: 700px;
- margin-left: auto;
- margin-right: auto;
+:root:not([data-theme="dark"]) .navbar .clean-btn svg {
+ filter: brightness(0.2);
+}
+.navbar .clean-btn svg {
+ width: 16px;
+ opacity: 1;
+}
+.navbar .clean-btn:hover svg {
+ filter: brightness(1.1);
+}
+.navbar .clean-btn.navbar-sidebar__back {
+ margin-left: 0;
+ width: fit-content;
+ margin-top: 15px;
+ color: var(--text-primary);
+ height: 30px !important;
+ padding: 0 0.7rem !important;
+ margin-left: 15px;
+}
+.navbar .clean-btn.navbar-sidebar__close {
+ width: 32px;
+ height: 32px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+.navbar .clean-btn.navbar-sidebar__close svg {
+ width: 13px;
+}
+.navbar .clean-btn.navbar__toggle:hover {
+ opacity: 0.5 !important;
+}
+.navbar .clean-btn.navbar__toggle,
+.navbar .navbar-sidebar__close {
+ background: transparent !important;
+ border: 0 !important;
+ box-shadow: none !important;
+}
+.navbar .clean-btn.navbar__toggle::before,
+.navbar .navbar-sidebar__close::before {
+ display: none !important;
+}
+.navbar .clean-btn.navbar__toggle svg {
+ width: 24px;
+}
+.navbar .clean-btn.navbar-sidebar__close svg {
+ width: 18px;
}
-.page-section-subtitle {
- text-align: center;
- font-size: 1.2rem;
- line-height: 1.3;
- margin-top: 20px;
- margin-bottom: 60px;
- font-weight: 500;
- color: var(--ifm-color-emphasis-600);
- max-width: 800px;
- margin-left: auto;
- margin-right: auto;
+nav button.DocSearch-Button {
+ @apply hidden;
}
-html[data-theme="dark"] .page-section-subtitle {
- color: var(--ifm-color-emphasis-400);
+button.DocSearch-Button {
+ @apply !pl-3 shiny-btn !rounded-md w-full;
+ height: 36px;
+ border: 1px solid transparent !important;
}
-/* Versioning */
+.pagination-nav__link {
+ color: inherit !important;
+ @apply shiny-btn;
+}
-.navbar .dropdown {
- display: none;
+.pagination-nav__sublabel {
+ @apply text-zinc-500 dark:!text-zinc-400;
}
-.plugin-id-default .navbar .dropdown:nth-child(1) {
- display: block;
+.pagination-nav__label {
+ color: inherit !important;
}
-.plugin-id-guides .navbar .dropdown:nth-child(2) {
- display: block;
+.DocSearch-Button-Key {
+ @apply dark:!bg-zinc-600;
+ transform: scale(0.8);
+}
+.DocSearch-Button-Key:nth-child(2) {
+ @apply !text-sm;
}
-.plugin-id-api .navbar .dropdown:nth-child(3) {
- display: block;
+.DocSearch-Button-Keys {
+ @apply mt-[2px];
}
-@media (max-width: 992px) {
- .navbar__items--right .dropdown {
- display: none;
- }
+.DocSearch-Search-Icon {
+ @apply !text-zinc-400 dark:!text-zinc-100 !w-5 !h-5;
+}
+.DocSearch-Button-Container .DocSearch-Search-Icon {
+ @apply !w-4 !h-4;
}
-/* Navigation */
+.DocSearch-Form {
+ @apply !shadow-none !rounded-xl border !border-zinc-500;
+}
-html[data-theme="dark"] body .navbar {
- background: var(--ifm-background-color);
+.DocSearch-Button-Placeholder {
+ @apply !text-sm;
}
-.navbar__logo img {
- height: 100%;
- max-height: 30px;
- min-width: 120px;
- margin-right: -25px;
- margin-top: 3px;
+.DocSearch-Input {
+ @apply !text-base;
}
-html[data-theme="light"] body .navbar__logo img {
- content: url("/img/brand/HF_Black.svg") !important;
+.DocSearch-Modal {
+ @apply !rounded-xl;
}
-.navbar__logo:hover img {
- opacity: 0.8;
+.breadcrumbs {
+ flex-wrap: wrap;
+ padding-left: 0 !important;
+ padding-top: 0 !important;
+ margin-top: 0px !important;
}
-.navbar__title {
- font-size: 22px;
+.breadcrumbs,
+.breadcrumbs__item {
+ position: relative;
+ display: flex;
+ align-items: center;
+ padding-left: 0;
}
-.navbar__items--right {
- flex-direction: row-reverse;
- gap: 10px;
+.breadcrumbs__item {
+ @apply !text-lg;
}
-/* Search */
+.breadcrumbs__item--active .breadcrumbs__link {
+ background: transparent !important;
+ font-weight: 700;
+}
-body .DocSearch-Button {
- height: 32px;
- border-radius: 2rem;
- font-size: 0.9rem;
- width: 170px;
- padding: 0 10px 0 14px;
- color: var(--ifm-navbar-search-input-color);
- background: var(--ifm-navbar-search-input-background-color);
- border-color: var(--ifm-color-emphasis-300);
- border: 1px solid var(--ifm-color-emphasis-300);
-}
-html[data-theme="dark"] body .DocSearch-Button {
- background: #3b3d4080;
- border: 1px solid #4c505658;
-}
-body .DocSearch-Button:hover,
-body .DocSearch-Button:focus {
- border-color: var(--ifm-color-primary) !important;
- background: var(--ifm-navbar-search-input-background-color);
- box-shadow: 0 0 0 1px var(--ifm-color-primary);
-}
-body .DocSearch-Modal,
-body .DocSearch-Footer {
- background: var(--ifm-background-color);
-}
-body .DocSearch-Form {
- background: var(--ifm-color-emphasis-200);
- box-shadow: inset 0 0 0 2px var(--ifm-color-primary);
-}
-body .DocSearch-Button-Placeholder {
- font-size: 14px;
+.menu * {
+ list-style-type: none;
}
-body .DocSearch-Search-Icon {
- width: 16px;
+
+.tocCollapsible_node_modules-\@docusaurus-theme-classic-lib-theme-TOCCollapsible-styles-module {
+ font-weight: 600;
}
-body .DocSearch-Hit-source,
-body .DocSearch-Modal {
- background: var(--ifm-background-color);
+
+.table-of-contents__link {
+ font-size: 14px !important;
+ line-height: 1.4 !important;
+ font-weight: 500 !important;
}
-@media (max-width: 996px) {
- body .navbar__items--right > :last-child {
- position: relative;
- margin-right: -20px;
- }
+.table-of-contents {
+ padding: 10px 0 !important;
}
-@media (max-width: 750px) {
- body .DocSearch-Button {
- width: 40px;
- padding: 0 12px 0 10px;
- }
+.table-of-contents > li {
+ margin-bottom: 12px !important;
+ margin-left: 25px !important;
}
-/* Github icon */
+aside {
+ border: 0px !important;
+}
-.github {
- padding: var(--ifm-navbar-item-padding-vertical);
+.footer {
+ width: 100vw;
+ max-width: 100vw;
+ overflow: hidden;
}
-.github::before {
- display: block;
- background-image: url("/img/github.svg");
- background-size: contain;
- content: "";
- width: 24px;
- height: 24px;
+.footer__item a {
+ display: flex;
+ white-space: nowrap;
+ flex-direction: row;
+ align-items: center;
}
-.github svg {
- display: none;
+.footer__link-item {
+ font-weight: 400;
+ opacity: 0.7;
+ font-size: 14px;
}
-.github:hover {
+[data-theme="dark"] .footer__link-item {
opacity: 0.7;
}
-html[data-theme="dark"] .github::before {
- filter: invert(100%);
+[data-theme="dark"] .footer__title {
+ color: white;
}
-html[data-theme="dark"] .navbar-sidebar .github {
- filter: invert(0%);
- padding: var(--ifm-menu-link-padding-vertical) var(--ifm-menu-link-padding-horizontal);
+[data-theme="light"] .footer__link-item {
+ color: #334155;
}
-.navbar-sidebar .github::before {
- width: 18px;
- height: 18px;
+[data-theme="light"] .footer__title {
+ color: #334155;
}
-.navbar-sidebar .github {
- display: flex;
- gap: 5px;
+[data-theme="light"] .footer__copyright {
+ color: #334155;
}
-.navbar-sidebar--show .github {
- padding: var(--ifm-menu-link-padding-vertical) var(--ifm-menu-link-padding-horizontal);
+.footer__copyright {
+ margin-top: 60px;
+ font-size: 14px;
}
-.navbar__inner .github {
- font-size: 0;
+body.dark {
+ --text-primary: #fff;
+ --text-secondary: #1c1c1d;
+ --background: var(--text-secondary);
}
-html[data-theme="dark"] .theme-doc-sidebar-container {
- background: #494b5024;
+body:not(.dark) {
+ --text-primary: #1c1c1d;
+ --text-secondary: #fff;
+ --background: var(--text-secondary);
}
-.theme-doc-sidebar-container .menu {
- padding-bottom: 60px;
+body {
+ margin: 0;
+ padding: 0;
+ font-family: Figtree;
}
-/* Docs */
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+ font-family: Inter;
+ color: var(--text-primary);
+ line-height: 1.4 !important;
+ @apply !text-transparent font-extrabold bg-clip-text bg-gradient-to-b from-zinc-800/60 via-zinc-800 to-zinc-800/60 dark:from-zinc-200/60 dark:via-zinc-200 dark:to-zinc-200/60;
+}
-aside {
- background: var(--ifm-background-color);
+button,
+a {
+ cursor: pointer;
+}
+a {
+ @apply text-yellow-500;
}
-.breadcrumbs__link {
- font-weight: 600;
+/* Typography */
+h1 {
+ @apply text-5xl font-extrabold;
+}
+h2 {
+ @apply text-4xl font-bold;
+}
+h3 {
+ @apply text-2xl font-bold;
+}
+h4 {
+ @apply text-xl font-bold;
+}
+h5 {
+ @apply text-lg font-semibold;
+}
+h6 {
+ @apply text-base font-semibold;
}
-/* Api */
+@screen md {
+ .h1 {
+ @apply text-6xl;
+ }
-.api-docs__monorepo-card-image {
- margin-right: 10px;
-}
+ .h2 {
+ @apply text-5xl;
+ }
-.api-docs__monorepo-column {
- margin-bottom: 15px;
+ .h3 {
+ @apply text-4xl;
+ }
}
-.api-docs__monorepo-card {
- display: flex;
- flex-direction: column;
- justify-content: space-between;
+/* Remark */
+
+main a[title="more"] {
+ @apply shiny-btn relative flex items-center !w-full pl-[188px] pr-4 py-3 !text-orange-500 font-bold no-underline;
}
-.api-docs__monorepo-card-title {
- display: flex;
- align-items: center;
- gap: 10px;
+/* main a[title="more"]::before {
+ @apply !text-zinc-600 dark:!text-white !mr-1 !pr-[1px];
+ display: inline-block !important;
+ content: "Read more about" !important;
+} */
+
+main a[title="more"]::after {
+ @apply mr-3 h-5 absolute left-4 !text-zinc-600 dark:!text-white font-normal;
+ display: inline-block;
+ content: "Read more about";
+ /* background-image: url(/static/img/bookmark.svg); */
+ background-size: contain;
+ background-repeat: no-repeat;
+ padding-left: 30px;
+ line-height: 19px;
}
-.api-link {
- display: block;
- width: fit-content;
- border: 1px solid var(--ifm-color-emphasis-300);
- border-radius: var(--ifm-pagination-nav-border-radius);
- line-height: var(--ifm-heading-line-height);
- padding: var(--ifm-global-spacing);
- transition: border-color var(--ifm-transition-fast) var(--ifm-transition-timing-default);
+/* Code blocks */
+
+code .api-type__type {
+ color: rgb(78, 201, 176);
}
-.api-link-title {
- color: var(--ifm-color-content-secondary);
- font-size: var(--ifm-h5-font-size);
- font-weight: var(--ifm-heading-font-weight);
- margin-bottom: 0.25rem;
+code .api-type__symbol {
+ color: white;
}
-.api-link-sub-title {
- font-size: var(--ifm-h4-font-size);
- font-weight: var(--ifm-heading-font-weight);
- word-break: break-word;
+/* Buttons */
+.btn,
+.btn-sm {
+ @apply text-sm font-medium inline-flex items-center justify-center border border-transparent rounded-full transition duration-150 ease-in-out;
}
-.api-link-sub-title p {
- margin: 10px 0 0;
+.btn {
+ @apply px-4 py-1.5;
}
-.api-docs__monorepo-card-more p {
- margin: 0;
+.btn-sm {
+ @apply px-3 py-1;
}
-/* Footer */
+/* Forms */
+input[type="search"]::-webkit-search-decoration,
+input[type="search"]::-webkit-search-cancel-button,
+input[type="search"]::-webkit-search-results-button,
+input[type="search"]::-webkit-search-results-decoration {
+ -webkit-appearance: none;
+}
-html[data-theme="light"] footer {
- --ifm-footer-background-color: #f5f5f5;
- --section-background: var(--ifm-background-surface-color);
+.form-input,
+.form-textarea,
+.form-multiselect,
+.form-select,
+.form-checkbox,
+.form-radio {
+ @apply bg-zinc-800 border border-transparent focus:border-blue-500;
}
-html[data-theme="dark"] footer {
- --ifm-footer-background-color: #141414;
- --section-background: var(--ifm-background-surface-color);
+.form-input,
+.form-textarea,
+.form-multiselect,
+.form-select,
+.form-checkbox {
+ @apply rounded;
}
-.footer__copyright {
- margin-top: 60px;
- font-size: 12px;
+.form-input,
+.form-textarea,
+.form-multiselect,
+.form-select {
+ @apply text-zinc-200 text-sm px-3 py-1.5;
}
-html[data-theme="light"] .footer__copyright {
- color: var(--ifm-color-emphasis-600);
+.form-input,
+.form-textarea {
+ @apply placeholder-zinc-500;
}
-html[data-theme="dark"] .footer__copyright {
- color: var(--ifm-color-emphasis-400);
+.form-select {
+ @apply pr-10;
}
-.footer__item a {
- font-size: 14px;
- font-weight: 600;
- color: var(--ifm-color-emphasis-600);
+.form-checkbox,
+.form-radio {
+ @apply text-blue-600 rounded-sm;
}
-html[data-theme="dark"] .footer__item a {
- color: var(--ifm-color-emphasis-400);
+/* Chrome, Safari and Opera */
+.no-scrollbar::-webkit-scrollbar {
+ display: none;
}
-@media (max-width: 996px) {
- .footer__link-item {
- text-align: center;
- }
- .footer__title {
- text-align: center;
- }
- .footer__item {
- text-align: center;
- }
+.no-scrollbar {
+ -ms-overflow-style: none; /* IE and Edge */
+ scrollbar-width: none; /* Firefox */
}
-/* Newsletter */
+.form-input:focus,
+.form-textarea:focus,
+.form-multiselect:focus,
+.form-select:focus,
+.form-checkbox:focus,
+.form-radio:focus {
+ @apply ring-0;
+}
-footer #mc_embed_signup {
- background: transparent;
+/* Hamburger button */
+.hamburger svg > *:nth-child(1),
+.hamburger svg > *:nth-child(2),
+.hamburger svg > *:nth-child(3) {
+ transform-origin: center;
+ transform: rotate(0deg);
}
-footer #mc_embed_signup .foot {
- text-align: left;
+.hamburger svg > *:nth-child(1) {
+ transition:
+ y 0.1s 0.25s ease-in,
+ transform 0.22s cubic-bezier(0.55, 0.055, 0.675, 0.19),
+ opacity 0.1s ease-in;
}
-footer form #mc_embed_signup_scroll {
- display: flex;
+.hamburger svg > *:nth-child(2) {
+ transition: transform 0.22s cubic-bezier(0.55, 0.055, 0.675, 0.19);
}
-footer form p {
- display: flex;
+.hamburger svg > *:nth-child(3) {
+ transition:
+ y 0.1s 0.25s ease-in,
+ transform 0.22s cubic-bezier(0.55, 0.055, 0.675, 0.19),
+ width 0.1s 0.25s ease-in;
}
-footer form p a {
- display: flex;
- padding-top: 20px;
- max-width: 140px;
+.hamburger.active svg > *:nth-child(1) {
+ opacity: 0;
+ y: 11;
+ transform: rotate(225deg);
+ transition:
+ y 0.1s ease-out,
+ transform 0.22s 0.12s cubic-bezier(0.215, 0.61, 0.355, 1),
+ opacity 0.1s 0.12s ease-out;
}
-footer #mc_embed_signup input.email {
- padding: 4px 14px;
- border-radius: 8px;
- height: 40px;
- margin-right: 5px;
- background: var(--ifm-background-color);
- border-color: var(--ifm-color-secondary-light);
- box-shadow: none;
- border: 1px solid var(--ifm-color-emphasis-300);
- font-weight: 600;
+.hamburger.active svg > *:nth-child(2) {
+ transform: rotate(225deg);
+ transition: transform 0.22s 0.12s cubic-bezier(0.215, 0.61, 0.355, 1);
}
-html[data-theme="dark"] footer #mc_embed_signup input.email {
- color: white;
- border: 1px solid var(--ifm-color-emphasis-200);
+.hamburger.active svg > *:nth-child(3) {
+ y: 11;
+ transform: rotate(135deg);
+ transition:
+ y 0.1s ease-out,
+ transform 0.22s 0.12s cubic-bezier(0.215, 0.61, 0.355, 1),
+ width 0.1s ease-out;
}
-html[data-theme="dark"] footer #mc_embed_signup input.email::placeholder {
- color: rgb(204, 204, 204);
+/* Custom Swiper styles */
+.swiper-button-disabled {
+ @apply opacity-50 cursor-default pointer-events-none;
}
-footer #mc_embed_signup .button {
- color: var(--ifm-button-color);
- background: var(--ifm-color-primary);
- font-weight: 600;
- box-shadow: 0px 2px 12px var(--box-shadow-primary-light);
- transition: all 150ms ease-in-out;
- padding: 4px 26px !important;
- border-radius: 8px;
- height: 40px !important;
- width: fit-content !important;
+.swiper-slide {
+ @apply opacity-80;
}
-footer #mc_embed_signup .button:hover {
- background: var(--ifm-color-primary-dark);
- box-shadow: 0px 4px 16px var(--box-shadow-primary-strong);
+.swiper-slide.swiper-slide-active {
+ @apply opacity-100;
}
-footer #mc_embed_signup .button:hover {
- background: var(--ifm-color-primary-darker);
+.swiper-slide {
+ height: auto !important;
+ align-self: stretch !important;
+}
+.swiper-content {
+ height: 100% !important;
}
-@media (max-width: 992px) {
- footer #mc_embed_signup .foot {
- width: 0;
+/* Pulsing animation */
+@keyframes pulseLoop {
+ 0% {
+ opacity: 0;
+ transform: scale(0.25) translateZ(0);
}
- footer form #mc_embed_signup_scroll {
- max-width: calc(100vw - 30px);
- margin: auto;
- justify-content: center;
+
+ 30% {
+ opacity: 0.4;
}
- footer form p a {
- display: flex;
- justify-content: center;
+
+ 70% {
+ opacity: 0;
}
- footer form p {
- justify-content: center;
+
+ 80% {
+ transform: scale(1) translateZ(0);
}
}
-@media (max-width: 400px) {
- footer form #mc_embed_signup_scroll {
- flex-direction: column;
- max-width: calc(100vw - 30px);
+.pulse {
+ opacity: 0;
+ transform-origin: center;
+ animation: pulseLoop 12000ms linear infinite;
+}
+
+.pulse-1 {
+ animation-delay: -4000ms;
+}
+
+.pulse-2 {
+ animation-delay: -8000ms;
+}
+
+.translate-z-0 {
+ transform: translateZ(0);
+}
+
+.api-link {
+ @apply border border-zinc-200 dark:border-zinc-800 rounded-md px-5 py-3 w-fit;
+ @apply bg-gradient-to-br from-zinc-50 to-zinc-100 border-zinc-200 text-zinc-900;
+ @apply dark:bg-gradient-to-br dark:from-zinc-900 dark:to-zinc-800 dark:border-zinc-700;
+ @apply dark:text-zinc-100 h-full;
+}
+
+.api-link-title {
+ @apply text-lg font-semibold text-zinc-700 dark:text-zinc-200;
+}
+
+.api-link-sub-title p {
+ @apply m-0;
+}
+
+.api-link-sub-title a {
+ @apply text-sm;
+}
+
+/**
+ * ==============================================
+ * Dot Elastic
+ * ==============================================
+ */
+.dot-elastic {
+ position: relative;
+ width: 10px;
+ height: 10px;
+ border-radius: 5px;
+ background-color: #9880ff;
+ color: #9880ff;
+ animation: dot-elastic 1s infinite linear;
+}
+.dot-elastic::before,
+.dot-elastic::after {
+ content: "";
+ display: inline-block;
+ position: absolute;
+ top: 0;
+}
+.dot-elastic::before {
+ left: -15px;
+ width: 10px;
+ height: 10px;
+ border-radius: 5px;
+ background-color: #9880ff;
+ color: #9880ff;
+ animation: dot-elastic-before 1s infinite linear;
+}
+.dot-elastic::after {
+ left: 15px;
+ width: 10px;
+ height: 10px;
+ border-radius: 5px;
+ background-color: #9880ff;
+ color: #9880ff;
+ animation: dot-elastic-after 1s infinite linear;
+}
+
+@keyframes dot-elastic-before {
+ 0% {
+ transform: scale(1, 1);
+ }
+ 25% {
+ transform: scale(1, 1.5);
+ }
+ 50% {
+ transform: scale(1, 0.67);
+ }
+ 75% {
+ transform: scale(1, 1);
+ }
+ 100% {
+ transform: scale(1, 1);
+ }
+}
+@keyframes dot-elastic {
+ 0% {
+ transform: scale(1, 1);
+ }
+ 25% {
+ transform: scale(1, 1);
+ }
+ 50% {
+ transform: scale(1, 1.5);
+ }
+ 75% {
+ transform: scale(1, 1);
+ }
+ 100% {
+ transform: scale(1, 1);
+ }
+}
+@keyframes dot-elastic-after {
+ 0% {
+ transform: scale(1, 1);
+ }
+ 25% {
+ transform: scale(1, 1);
+ }
+ 50% {
+ transform: scale(1, 0.67);
+ }
+ 75% {
+ transform: scale(1, 1.5);
+ }
+ 100% {
+ transform: scale(1, 1);
}
}
-/* Comparison */
+/* Mermaid */
+
+/* Center */
-.comparison-table {
- max-width: 100%;
- overflow-x: auto;
+.docusaurus-mermaid-container .section-root circle,
+.docusaurus-mermaid-container .section-root polygon {
+ @apply !fill-zinc-400;
}
-.comparison-table table {
- display: table;
- width: 100%;
+.docusaurus-mermaid-container p {
+ @apply !text-inherit;
}
-.comparison-table td:first-child {
- font-weight: 800;
+/* Arrow lines */
+.docusaurus-mermaid-container .lineWrapper line {
+ @apply !stroke-zinc-500;
+}
+.docusaurus-mermaid-container #arrowhead {
+ @apply !fill-zinc-500;
}
-.comparison-table th {
- white-space: nowrap;
+/* Root */
+.docusaurus-mermaid-container .section-root text {
+ @apply !fill-zinc-200;
+}
+
+/* Main section */
+.docusaurus-mermaid-container .section--1 path,
+.docusaurus-mermaid-container .section--1 polygon,
+.docusaurus-mermaid-container .section--1 rect,
+.docusaurus-mermaid-container .section--1 circle {
+ @apply !fill-yellow-600;
+}
+.docusaurus-mermaid-container .section--1 line {
+ @apply !stroke-yellow-500;
+}
+.docusaurus-mermaid-container .section-edge--1 {
+ @apply !stroke-yellow-400;
}
-/* Docs */
+/* Other sections */
+.docusaurus-mermaid-container .section-0 path,
+.docusaurus-mermaid-container .section-0 polygon,
+.docusaurus-mermaid-container .section-0 rect,
+.docusaurus-mermaid-container .section-0 circle {
+ @apply !fill-indigo-600;
+}
+.docusaurus-mermaid-container .section-0 line {
+ @apply !stroke-indigo-400;
+}
+.docusaurus-mermaid-container .section-edge-0 {
+ @apply !stroke-indigo-400;
+}
-.row-flex {
- display: flex;
- flex-wrap: nowrap;
- gap: 15px;
+.docusaurus-mermaid-container .section-1 path,
+.docusaurus-mermaid-container .section-1 polygon,
+.docusaurus-mermaid-container .section-1 rect,
+.docusaurus-mermaid-container .section-1 circle {
+ @apply !fill-blue-500;
+}
+.docusaurus-mermaid-container .section-1 line {
+ @apply !stroke-blue-400;
+}
+.docusaurus-mermaid-container .section-edge-1 {
+ @apply !stroke-blue-400;
+}
+
+.docusaurus-mermaid-container .section-2 path,
+.docusaurus-mermaid-container .section-2 polygon,
+.docusaurus-mermaid-container .section-2 rect,
+.docusaurus-mermaid-container .section-2 circle {
+ @apply !fill-teal-600;
+}
+.docusaurus-mermaid-container .section-2 line {
+ @apply !stroke-teal-400;
+}
+.docusaurus-mermaid-container .section-edge-2 {
+ @apply !stroke-teal-400;
+}
+
+.docusaurus-mermaid-container .section-3 path,
+.docusaurus-mermaid-container .section-3 polygon,
+.docusaurus-mermaid-container .section-3 rect,
+.docusaurus-mermaid-container .section-3 circle {
+ @apply !fill-green-600;
+}
+.docusaurus-mermaid-container .section-3 line {
+ @apply !stroke-green-400;
+}
+.docusaurus-mermaid-container .section-edge-3 {
+ @apply !stroke-green-400;
+}
+
+.docusaurus-mermaid-container .section-4 path,
+.docusaurus-mermaid-container .section-4 polygon,
+.docusaurus-mermaid-container .section-4 rect,
+.docusaurus-mermaid-container .section-4 circle {
+ @apply !fill-pink-600;
+}
+.docusaurus-mermaid-container .section-4 line {
+ @apply !stroke-pink-400;
+}
+.docusaurus-mermaid-container .section-edge-4 {
+ @apply !stroke-pink-400;
+}
+
+.docusaurus-mermaid-container .section-5 path,
+.docusaurus-mermaid-container .section-5 polygon,
+.docusaurus-mermaid-container .section-5 rect,
+.docusaurus-mermaid-container .section-5 circle {
+ @apply !fill-cyan-600;
+}
+.docusaurus-mermaid-container .section-5 line {
+ @apply !stroke-cyan-400;
+}
+.docusaurus-mermaid-container .section-edge-5 {
+ @apply !stroke-cyan-400;
+}
+
+.docusaurus-mermaid-container .section-6 path,
+.docusaurus-mermaid-container .section-6 polygon,
+.docusaurus-mermaid-container .section-6 rect,
+.docusaurus-mermaid-container .section-6 circle {
+ @apply !fill-emerald-600;
+}
+.docusaurus-mermaid-container .section-6 line {
+ @apply !stroke-emerald-400;
+}
+.docusaurus-mermaid-container .section-edge-6 {
+ @apply !stroke-emerald-400;
+}
+
+/* Tippy */
+
+.tippy-box {
+ @apply !bg-zinc-900;
+}
+.tippy-box .tippy-arrow {
+ @apply text-zinc-900;
+}
+
+/* Tailwind-like shine animation for direct CSS use */
+@keyframes border-shine {
+ 0% {
+ background-position: 0% 0%;
+ }
+ 50% {
+ background-position: 100% 100%;
+ }
+ 100% {
+ background-position: 0% 0%;
+ }
+}
+
+.shine-animate {
+ animation: border-shine var(--duration, 2s) infinite linear;
}
diff --git a/documentation/src/guides.ts b/documentation/src/guides.ts
new file mode 100644
index 000000000..6cba9b3e0
--- /dev/null
+++ b/documentation/src/guides.ts
@@ -0,0 +1,117 @@
+/* eslint-disable @typescript-eslint/no-var-requires */
+import { Book, FlaskConical } from "lucide-react";
+
+import { Section } from "./modules";
+import { isBrowser } from "./utils/is-browser";
+
+const ReactIcon = isBrowser() ? require("../static/img/integration-react.svg").default : () => null;
+const HFIcon = isBrowser() ? require("../static/img/integration-hf.svg").default : () => null;
+const SocketsIcon = isBrowser() ? require("../static/img/integration-sockets.svg").default : () => null;
+const TypescriptIcon = isBrowser() ? require("../static/img/typescript.svg").default : () => null;
+
+export const guides: Section[] = [
+ {
+ label: "Getting Started",
+ description: "Overview of the available integrations",
+ isPackage: false,
+ dir: "getting-started",
+ paths: ["getting-started"],
+ img: Book,
+ text: "drop-shadow-sm !text-indigo-500 dark:!text-indigo-400",
+ textAction:
+ "focus:!text-indigo-500 focus:dark:!text-indigo-400 active:!text-indigo-600 active:dark:!text-indigo-300",
+ textHover: "hover:!text-indigo-500 hover:dark:!text-indigo-400",
+ icon: "group-hover:shadow-indigo-200 dark:group-hover:bg-indigo-500 bg-indigo-400 dark:bg-indigo-500",
+ iconHover:
+ "group-hover:shadow-indigo-200 dark:group-hover:bg-indigo-500 group-hover:bg-indigo-400 group-hover:dark:bg-indigo-500 group-hover:!bg-opacity-40",
+ border: "border-indigo-500 dark:border-indigo-400",
+ borderHover: "hover:border-indigo-500 hover:dark:border-indigo-400",
+ category: "Guides",
+ },
+ {
+ label: "Core",
+ description: "Overview of the available integrations",
+ isPackage: false,
+ dir: "core",
+ paths: ["core"],
+ img: HFIcon,
+ text: "drop-shadow-sm !text-green-500 dark:!text-green-400",
+ textAction: "focus:!text-green-500 focus:dark:!text-green-400 active:!text-green-600 active:dark:!text-green-300",
+ textHover: "hover:!text-green-500 hover:dark:!text-green-400",
+ icon: "group-hover:shadow-green-200 dark:group-hover:bg-green-500 bg-green-400 dark:bg-green-500 !bg-opacity-30",
+ iconHover:
+ "group-hover:shadow-green-200 dark:group-hover:bg-green-500 group-hover:bg-green-400 group-hover:dark:bg-green-500 !bg-opacity-40",
+ border: "border-green-500 dark:border-green-400",
+ borderHover: "hover:border-green-500 hover:dark:border-green-400",
+ category: "Guides",
+ },
+ {
+ label: "Sockets",
+ description: "Overview of the available integrations",
+ isPackage: false,
+ dir: "sockets",
+ paths: ["sockets"],
+ img: SocketsIcon,
+ text: "drop-shadow-sm !text-blue-500 dark:!text-blue-400",
+ textAction: "focus:!text-blue-500 focus:dark:!text-blue-400 active:!text-blue-600 active:dark:!text-blue-300",
+ textHover: "hover:!text-blue-500 hover:dark:!text-blue-400",
+ icon: "group-hover:shadow-blue-200 dark:group-hover:bg-blue-500 bg-blue-400 dark:bg-blue-500 !bg-opacity-30",
+ iconHover:
+ "group-hover:shadow-blue-200 dark:group-hover:bg-blue-500 group-hover:bg-blue-400 group-hover:dark:bg-blue-500 !bg-opacity-40",
+ border: "border-blue-500 dark:border-blue-400",
+ borderHover: "hover:border-blue-500 hover:dark:border-blue-400",
+ category: "Guides",
+ },
+ {
+ label: "React",
+ description: "Overview of the available integrations",
+ isPackage: false,
+ dir: "react",
+ paths: ["react"],
+ img: ReactIcon,
+ text: "drop-shadow-sm !text-sky-500 dark:!text-sky-400",
+ textAction: "focus:!text-sky-500 focus:dark:!text-sky-400 active:!text-sky-600 active:dark:!text-sky-300",
+ textHover: "hover:!text-sky-500 hover:dark:!text-sky-400",
+ icon: "group-hover:shadow-sky-200 dark:group-hover:bg-sky-500 bg-sky-400 dark:bg-sky-500 !bg-opacity-30",
+ iconHover:
+ "group-hover:shadow-sky-200 dark:group-hover:bg-sky-500 group-hover:bg-sky-400 group-hover:dark:bg-sky-500 !bg-opacity-40",
+ border: "border-sky-500 dark:border-sky-400",
+ borderHover: "hover:border-sky-500 hover:dark:border-sky-400",
+ category: "Guides",
+ },
+ {
+ label: "Typescript",
+ description: "Learn how to use Typescript with Hyper Fetch",
+ isPackage: false,
+ dir: "typescript",
+ paths: ["typescript"],
+ img: TypescriptIcon,
+ text: "drop-shadow-sm !text-blue-500 dark:!text-blue-400",
+ textAction: "focus:!text-blue-500 focus:dark:!text-blue-400 active:!text-blue-600 active:dark:!text-blue-300",
+ textHover: "hover:!text-blue-500 hover:dark:!text-blue-400",
+ icon: "group-hover:shadow-blue-200 dark:group-hover:bg-blue-500 bg-blue-400 dark:bg-blue-500 !bg-opacity-30",
+ iconHover:
+ "group-hover:shadow-blue-200 dark:group-hover:bg-blue-500 group-hover:bg-blue-400 group-hover:dark:bg-blue-500 !bg-opacity-40",
+ border: "border-blue-500 dark:border-blue-400",
+ borderHover: "hover:border-blue-500 hover:dark:border-blue-400",
+ category: "Guides",
+ },
+ {
+ label: "Testing",
+ description: "Overview of the available integrations",
+ isPackage: false,
+ dir: "testing",
+ paths: ["testing"],
+ img: FlaskConical,
+ text: "drop-shadow-sm !text-purple-500 dark:!text-purple-400",
+ textAction:
+ "focus:!text-purple-500 focus:dark:!text-purple-400 active:!text-purple-600 active:dark:!text-purple-300",
+ textHover: "hover:!text-purple-500 hover:dark:!text-purple-400",
+ icon: "group-hover:shadow-purple-200 dark:group-hover:bg-purple-500 bg-purple-400 dark:bg-purple-500 !bg-opacity-30",
+ iconHover:
+ "group-hover:shadow-purple-200 dark:group-hover:bg-purple-500 group-hover:bg-purple-400 group-hover:dark:bg-purple-500 !bg-opacity-40",
+ border: "border-purple-500 dark:border-purple-400",
+ borderHover: "hover:border-purple-500 hover:dark:border-purple-400",
+ category: "Guides",
+ },
+];
diff --git a/documentation/src/hooks/use-filtered-sidebar.ts b/documentation/src/hooks/use-filtered-sidebar.ts
new file mode 100644
index 000000000..464864a99
--- /dev/null
+++ b/documentation/src/hooks/use-filtered-sidebar.ts
@@ -0,0 +1,43 @@
+// Filter out pages from menu
+const skipPages = ["props", "theming"];
+
+export const getDocName = (item) => {
+ if (item.label === "index") {
+ const label = item.href.split("/");
+ const name = label.reverse().find(Boolean);
+ return {
+ ...item,
+ label: name,
+ };
+ }
+ return item;
+};
+
+export const pickName = (categories) => {
+ return categories.map((category) => {
+ return {
+ ...category,
+ items: category.items?.map(getDocName),
+ };
+ });
+};
+
+const skipItems = (categories) => {
+ return categories
+ .filter((category) => {
+ return !category.docId || !skipPages.some((page) => category.docId?.includes(page));
+ })
+ .map((category) => {
+ const newItems = category.items ? skipItems(category.items) : [];
+ const hasChildren = !!newItems.length;
+ const collapsible = hasChildren ? category.collapsible : undefined;
+ const collapsed = hasChildren ? category.collapsed : undefined;
+ const type = hasChildren ? category.type : "link";
+
+ return category.items ? { ...category, items: newItems, collapsible, collapsed, type } : category;
+ });
+};
+
+export const useFilteredSidebar = (items) => {
+ return pickName(skipItems(items));
+};
diff --git a/documentation/src/hooks/use-mouse-position.ts b/documentation/src/hooks/use-mouse-position.ts
new file mode 100644
index 000000000..b3f827d82
--- /dev/null
+++ b/documentation/src/hooks/use-mouse-position.ts
@@ -0,0 +1,27 @@
+import { useState, useEffect } from "react";
+
+interface MousePosition {
+ x: number;
+ y: number;
+}
+
+export default function useMousePosition(): MousePosition {
+ const [mousePosition, setMousePosition] = useState({
+ x: 0,
+ y: 0,
+ });
+
+ useEffect(() => {
+ const handleMouseMove = (event: MouseEvent) => {
+ setMousePosition({ x: event.clientX, y: event.clientY });
+ };
+
+ window.addEventListener("mousemove", handleMouseMove);
+
+ return () => {
+ window.removeEventListener("mousemove", handleMouseMove);
+ };
+ }, []);
+
+ return mousePosition;
+}
diff --git a/documentation/src/hooks/use-sidebar.ts b/documentation/src/hooks/use-sidebar.ts
new file mode 100644
index 000000000..b395d8d04
--- /dev/null
+++ b/documentation/src/hooks/use-sidebar.ts
@@ -0,0 +1,175 @@
+import React, { useMemo } from "react";
+import { useLocation } from "@docusaurus/router";
+import useGlobalData from "@docusaurus/useGlobalData";
+
+import { useVersion } from "./use-version";
+import { modules, Section } from "../modules";
+import { integrations } from "../integrations";
+import { guides } from "../guides";
+import { apiOverviewSection } from "../apis";
+
+type SidebarElement = {
+ link: {
+ path: string; // "/docs/components/"
+ label: string; // "Intro"
+ };
+};
+
+type Version = {
+ docs: Array<{
+ id: string;
+ path: string;
+ sidebar: string;
+ }>;
+ draftIds: unknown[];
+ isLast: boolean;
+ label: string; // "v1.0.0"
+ mainDocId: string; // "documentation/index"
+ name: string; // "current"
+ path: string; // "/docs"
+ sidebars: Record;
+};
+
+export type SidebarItem = {
+ name: string;
+ description: string;
+ index: number;
+ link: SidebarElement["link"];
+ img: React.ComponentType>;
+ active: boolean;
+ section: Section;
+ isNew?: boolean;
+ isPro?: boolean;
+};
+
+export const useSidebar = (options?: {
+ showAllPackages?: boolean;
+}): { sidebar: SidebarItem[]; activeItem: SidebarItem | null } => {
+ const location = useLocation();
+ const data = useGlobalData();
+
+ const [version] = useVersion();
+
+ const { showAllPackages = false } = options || {};
+ const { versions } = data["docusaurus-plugin-content-docs"].default as {
+ breadcrumbs: boolean;
+ path: string; // "/docs"
+ versions: Version[];
+ };
+
+ const currentVersion = versions.find((item: Version) => {
+ return item.label === version;
+ });
+
+ const sidebar: SidebarItem[] = useMemo(() => {
+ if (!currentVersion?.sidebars) return [];
+
+ const isApiPage = location.pathname.includes("/docs/api");
+ const isIntegrationsPage = location.pathname.includes("/docs/integrations");
+ const isGuidesPage = location.pathname.includes("/docs/guides");
+
+ return Object.values(currentVersion.sidebars)
+ .filter((value) => {
+ if (!value.link?.path) {
+ // eslint-disable-next-line no-console
+ console.log("You must update the sidebars. Missing path for the following item");
+ return false; // Ensure items without a path are filtered out
+ }
+
+ const linkPath = value.link.path;
+ if (showAllPackages) {
+ return linkPath.includes("/docs/api");
+ }
+ if (isApiPage) {
+ return linkPath.includes("/api");
+ }
+ if (isIntegrationsPage) {
+ return linkPath.includes("/integrations");
+ }
+ if (isGuidesPage) {
+ return linkPath.includes("/guides");
+ }
+ return (
+ !linkPath.includes("/docs/api") &&
+ !linkPath.includes("/docs/integrations") &&
+ !linkPath.includes("/docs/guides")
+ );
+ })
+ .map((value) => {
+ /**
+ * DO NOT CHANGE!
+ * @caution If it fails - you made mistake in the sidebar config :)
+ */
+ const pathParts = value.link.path.split("/");
+ const isNonDocs =
+ value.link.path.includes("/integrations") ||
+ value.link.path.includes("/guides") ||
+ value.link.path.includes("/api");
+ const componentName = isNonDocs ? pathParts[3] : pathParts[2];
+ const component = componentName.toLocaleLowerCase();
+
+ const allPackages = [
+ apiOverviewSection,
+ ...modules.filter((item) => item.isPackage),
+ ...integrations.filter((item) => item.isPackage),
+ ];
+
+ const findIndex = (items: Section[], comp: string) =>
+ items.findIndex((item) => item.paths.find((itemName) => itemName.toLowerCase() === comp));
+
+ let section: Section | undefined;
+ let index: number;
+ let prefix: string;
+
+ if (showAllPackages) {
+ const packageIndex = findIndex(allPackages, component);
+ section = allPackages[packageIndex];
+ index = packageIndex;
+ // Prefix determination might need refinement based on showAllPackages logic,
+ // defaulting to 'docs' or inferring from section path if needed.
+ prefix = "docs"; // Or determine more dynamically if required
+ } else if (isIntegrationsPage) {
+ const integrationIndex = findIndex(integrations, component);
+ section = integrations[integrationIndex];
+ index = integrationIndex;
+ prefix = "integrations";
+ } else if (isApiPage) {
+ const packageIndex = findIndex(allPackages, component);
+ section = allPackages[packageIndex];
+ index = packageIndex;
+ prefix = "api";
+ } else if (isGuidesPage) {
+ const pkgIndex = findIndex(guides, component);
+ section = guides[pkgIndex];
+ index = pkgIndex;
+ prefix = "guides";
+ } else {
+ const pkgIndex = findIndex(modules, component);
+ section = modules[pkgIndex];
+ index = pkgIndex;
+ prefix = "docs";
+ }
+
+ const active =
+ location.pathname.includes(`${prefix}/${component}/`) || location.pathname.endsWith(`${prefix}/${component}`);
+
+ return {
+ name: section?.label || componentName,
+ description: section?.description || "",
+ index,
+ link: value.link,
+ img: section?.img,
+ active,
+ section,
+ isNew: section?.isNew,
+ isPro: section?.isPro,
+ } satisfies SidebarItem;
+ })
+ .filter((item) => item.section && (!showAllPackages || item.section.isPackage))
+ .sort((a, b) => a.index - b.index);
+ }, [currentVersion.sidebars, location.pathname, showAllPackages]);
+
+ const activeItem = sidebar.find((item) => item.active) ?? null;
+
+ return { sidebar, activeItem };
+};
diff --git a/documentation/src/hooks/use-theme-listener.ts b/documentation/src/hooks/use-theme-listener.ts
new file mode 100644
index 000000000..c51a122f2
--- /dev/null
+++ b/documentation/src/hooks/use-theme-listener.ts
@@ -0,0 +1,38 @@
+import { useCallback, useEffect } from "react";
+import { useColorMode } from "@docusaurus/theme-common";
+
+export const useThemeListener = () => {
+ const { isDarkTheme } = useColorMode();
+
+ const html = document.documentElement;
+
+ const changeElement = useCallback((isDark: boolean) => {
+ if (isDark) {
+ html.classList.add("tw-dark");
+ document.body.setAttribute("arco-theme", "dark");
+ } else {
+ html.classList.remove("tw-dark");
+ document.body.removeAttribute("arco-theme");
+ }
+ }, []);
+
+ const observer = new MutationObserver((mutation) => {
+ const className = (mutation[0].target as any).className as string;
+ if ((className.includes("tw-dark") && !isDarkTheme) || (!className.includes("tw-dark") && isDarkTheme)) {
+ changeElement(isDarkTheme);
+ }
+ });
+
+ useEffect(() => {
+ observer.observe(document.documentElement, {
+ attributes: true,
+ attributeFilter: ["class"],
+ });
+ changeElement(isDarkTheme);
+ return () => {
+ observer.disconnect();
+ html.classList.remove("tw-dark");
+ document.body.removeAttribute("arco-theme");
+ };
+ }, [isDarkTheme]);
+};
diff --git a/documentation/src/hooks/use-toast.tsx b/documentation/src/hooks/use-toast.tsx
new file mode 100644
index 000000000..eb4cf3599
--- /dev/null
+++ b/documentation/src/hooks/use-toast.tsx
@@ -0,0 +1,238 @@
+/* eslint-disable default-case */
+/* eslint-disable @typescript-eslint/no-use-before-define */
+/* eslint-disable @typescript-eslint/no-shadow */
+
+// Inspired by react-hot-toast library
+import * as React from "react";
+import type { ToastProps } from "@site/src/components/ui/toast";
+
+const TOAST_LIMIT = 3;
+const TOAST_REMOVE_DELAY = 3000;
+
+type ToasterToast = ToastProps & {
+ id: string;
+ message?: React.ReactNode;
+ timestamp: number;
+};
+
+const actionTypes = {
+ ADD_TOAST: "ADD_TOAST",
+ UPDATE_TOAST: "UPDATE_TOAST",
+ DISMISS_TOAST: "DISMISS_TOAST",
+ REMOVE_TOAST: "REMOVE_TOAST",
+} as const;
+
+let count = 0;
+
+function genId() {
+ count = (count + 1) % Number.MAX_SAFE_INTEGER;
+ return count.toString();
+}
+
+type ActionType = typeof actionTypes;
+
+type Action =
+ | {
+ type: ActionType["ADD_TOAST"];
+ toast: ToasterToast;
+ }
+ | {
+ type: ActionType["UPDATE_TOAST"];
+ toast: Partial;
+ }
+ | {
+ type: ActionType["DISMISS_TOAST"];
+ toastId?: ToasterToast["id"];
+ }
+ | {
+ type: ActionType["REMOVE_TOAST"];
+ toastId?: ToasterToast["id"];
+ };
+
+interface State {
+ toasts: ToasterToast[];
+}
+
+const memoryState: Record = {};
+const listeners: Record void>> = {};
+const toastTimeouts: Record>> = {};
+
+const addToRemoveQueue = (id: string, toastId: string) => {
+ if (!toastTimeouts[id]) {
+ toastTimeouts[id] = new Map();
+ }
+
+ if (toastTimeouts[id].has(toastId)) {
+ return;
+ }
+
+ const timeout = setTimeout(() => {
+ toastTimeouts[id].delete(toastId);
+ dispatch(id, {
+ type: "REMOVE_TOAST",
+ toastId,
+ });
+ }, TOAST_REMOVE_DELAY);
+
+ toastTimeouts[id].set(toastId, timeout);
+};
+
+export const reducer = (instanceId: string, state: State, action: Action): State => {
+ switch (action.type) {
+ case "ADD_TOAST":
+ return {
+ ...state,
+ toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT),
+ };
+
+ case "UPDATE_TOAST":
+ return {
+ ...state,
+ toasts: state.toasts.map((t) => (t.id === action.toast.id ? { ...t, ...action.toast } : t)),
+ };
+
+ case "DISMISS_TOAST": {
+ const { toastId } = action;
+
+ // ! Side effects ! - This could be extracted into a dismissToast() action,
+ // but I'll keep it here for simplicity
+ if (toastId) {
+ addToRemoveQueue(instanceId, toastId);
+ } else {
+ state.toasts.forEach((toast) => {
+ addToRemoveQueue(instanceId, toast.id);
+ });
+ }
+
+ return {
+ ...state,
+ toasts: state.toasts.map((t) =>
+ t.id === toastId || toastId === undefined
+ ? {
+ ...t,
+ open: false,
+ }
+ : t,
+ ),
+ };
+ }
+ case "REMOVE_TOAST":
+ if (action.toastId === undefined) {
+ return {
+ ...state,
+ toasts: [],
+ };
+ }
+ return {
+ ...state,
+ toasts: state.toasts.filter((t) => t.id !== action.toastId),
+ };
+ }
+};
+
+function dispatch(instanceId: string, action: Action) {
+ if (!memoryState[instanceId]) {
+ memoryState[instanceId] = { toasts: [] };
+ }
+ if (!listeners[instanceId]) {
+ listeners[instanceId] = [];
+ }
+
+ memoryState[instanceId] = reducer(instanceId, memoryState[instanceId], action);
+ listeners[instanceId].forEach((listener) => {
+ listener(memoryState[instanceId]);
+ });
+}
+
+type Toast = Omit & { instanceId: string };
+
+function toast({ instanceId, ...props }: Toast) {
+ const id = genId();
+
+ const update = (props: ToasterToast) =>
+ dispatch(instanceId, {
+ type: "UPDATE_TOAST",
+ toast: { ...props, id },
+ });
+ const dismiss = () => dispatch(instanceId, { type: "DISMISS_TOAST", toastId: id });
+
+ dispatch(instanceId, {
+ type: "ADD_TOAST",
+ toast: {
+ ...props,
+ id,
+ open: true,
+ onOpenChange: (open) => {
+ if (!open) dismiss();
+ },
+ },
+ });
+ return {
+ id,
+ dismiss,
+ update,
+ };
+}
+
+function useToast() {
+ const { id } = useToasterId();
+ const [state, setState] = React.useState(memoryState[id]);
+
+ React.useEffect(() => {
+ if (!listeners[id]) {
+ listeners[id] = [];
+ }
+ listeners[id].push(setState);
+ return () => {
+ const index = listeners[id].indexOf(setState);
+ if (index > -1) {
+ listeners[id].splice(index, 1);
+ }
+ };
+ }, []); // Only subscribe/unsubscribe on mount/unmount
+
+ return {
+ ...state,
+ toast: (props: ToastProps) =>
+ toast({ ...props, instanceId: id, timestamp: Date.now() + props.duration || TOAST_REMOVE_DELAY }),
+ dismiss: (toastId?: string) => dispatch(id, { type: "DISMISS_TOAST", toastId }),
+ };
+}
+
+export const usePreviewToast = () => {
+ const { id } = useToasterId();
+
+ return React.useCallback(
+ (props: ToastProps) =>
+ toast({ ...props, instanceId: id, timestamp: Date.now() + props.duration || TOAST_REMOVE_DELAY }),
+ [id],
+ );
+};
+
+// Toaster Context
+const ToasterIdContext = React.createContext<{ id: string }>({ id: "" });
+
+const { Provider } = ToasterIdContext;
+
+interface ToasterProviderProps {
+ children: React.ReactNode;
+ id?: string;
+}
+
+export function ToasterProvider({ children, id }: ToasterProviderProps) {
+ const generatedId = React.useId();
+ const value = React.useMemo(
+ () => ({
+ id: id ?? generatedId,
+ }),
+ [id, generatedId],
+ );
+ return {children} ;
+}
+
+function useToasterId() {
+ const contextId = React.useContext(ToasterIdContext);
+ return contextId;
+}
+
+export { useToast, toast };
diff --git a/documentation/src/hooks/use-version.ts b/documentation/src/hooks/use-version.ts
new file mode 100644
index 000000000..a6d7a45be
--- /dev/null
+++ b/documentation/src/hooks/use-version.ts
@@ -0,0 +1,18 @@
+import { useLocation } from "@docusaurus/router";
+
+import docsVersions from "../../versions.json";
+
+const getCurrentMajor = () => {
+ const latestVersion = docsVersions[0] || "v0.0.0";
+ const latestMajor = latestVersion[1];
+ return Number(latestMajor) + 1;
+};
+
+export const useVersion = () => {
+ const location = useLocation();
+ const isVersioned = location.pathname.includes("docs/v.");
+
+ const version = isVersioned ? location.pathname.split("/")[2] : `v${getCurrentMajor()}.0.0`;
+
+ return [version, isVersioned];
+};
diff --git a/documentation/src/integrations.ts b/documentation/src/integrations.ts
new file mode 100644
index 000000000..ce1f1f1ad
--- /dev/null
+++ b/documentation/src/integrations.ts
@@ -0,0 +1,182 @@
+/* eslint-disable @typescript-eslint/no-var-requires */
+import { Book } from "lucide-react";
+
+import { Section } from "./modules";
+import { isBrowser } from "./utils/is-browser";
+
+const AxiosIcon = isBrowser() ? require("../static/img/integration-axios.svg").default : () => null;
+// const ReactIcon = isBrowser() ? require("../static/img/integration-react.svg").default : () => null;
+// const NextIcon = isBrowser() ? require("../static/img/integration-next.svg").default : () => null;
+// const RemixIcon = isBrowser() ? require("../static/img/integration-remix.svg").default : () => null;
+// const AstroIcon = isBrowser() ? require("../static/img/integration-astro.svg").default : () => null;
+// const NestIcon = isBrowser() ? require("../static/img/integration-nest.svg").default : () => null;
+const GraphqlIcon = isBrowser() ? require("../static/img/integration-graphql.svg").default : () => null;
+// const RestIcon = isBrowser() ? require("../static/img/integration-rest.svg").default : () => null;
+// const StrapiIcon = isBrowser() ? require("../static/img/integration-strapi.svg").default : () => null;
+// const HasuraIcon = isBrowser() ? require("../static/img/integration-hasura.svg").default : () => null;
+// const AppwriteIcon = isBrowser() ? require("../static/img/integration-appwrite.svg").default : () => null;
+// const AirtableIcon = isBrowser() ? require("../static/img/integration-airtable.svg").default : () => null;
+// const MedusaIcon = isBrowser() ? require("../static/img/integration-medusa.svg").default : () => null;
+const FirebaseIcon = isBrowser() ? require("../static/img/integration-firebase.svg").default : () => null;
+// const SocketsIcon = isBrowser() ? require("../static/img/integration-sockets.svg").default : () => null;
+// const KindeIcon = isBrowser() ? require("../static/img/integration-kinde.svg").default : () => null;
+// const ClerkIcon = isBrowser() ? require("../static/img/integration-clerk.svg").default : () => null;
+// const MapboxIcon = isBrowser() ? require("../static/img/integration-mapbox.svg").default : () => null;
+// const GoogleMapsIcon = isBrowser() ? require("../static/img/integration-google-maps.svg").default : () => null;
+const OpenApiIcon = isBrowser() ? require("../static/img/integration-openapi.svg").default : () => null;
+const EslintIcon = isBrowser() ? require("../static/img/integration-eslint.svg").default : () => null;
+const HFIcon = isBrowser() ? require("../static/img/integration-hf.svg").default : () => null;
+
+export const integrations: Section[] = [
+ {
+ label: "Getting Started",
+ description: "Overview of the available integrations",
+ isPackage: false,
+ dir: "getting-started",
+ paths: ["getting-started"],
+ img: Book,
+ text: "drop-shadow-sm !text-green-500 dark:!text-green-400",
+ textAction: "focus:!text-green-500 focus:dark:!text-green-400 active:!text-green-600 active:dark:!text-green-300",
+ textHover: "hover:!text-green-500 hover:dark:!text-green-400",
+ icon: "group-hover:shadow-green-200 dark:group-hover:bg-green-500 bg-green-400 dark:bg-green-500",
+ iconHover:
+ "group-hover:shadow-green-200 dark:group-hover:bg-green-500 group-hover:bg-green-400 group-hover:dark:bg-green-500 group-hover:!bg-opacity-40",
+ border: "border-green-500 dark:border-green-400",
+ borderHover: "hover:border-green-500 hover:dark:border-green-400",
+ category: "docs",
+ },
+ {
+ label: "ESLint",
+ description: "ESLint rules to enforce more typescript best practices",
+ dir: "plugin-eslint",
+ isPackage: true,
+ paths: ["plugin-eslint"],
+ img: EslintIcon,
+ text: "drop-shadow-sm !text-zinc-500 dark:!text-zinc-300",
+ textAction: "focus:!text-zinc-500 focus:dark:!text-zinc-300 active:!text-zinc-600 active:dark:!text-zinc-200",
+ textHover: "hover:!text-zinc-500 hover:dark:!text-zinc-400",
+ icon: "group-hover:shadow-zinc-200 dark:group-hover:bg-zinc-300 bg-zinc-400 dark:bg-zinc-300 !bg-opacity-30",
+ iconHover:
+ "group-hover:shadow-zinc-200 dark:group-hover:bg-zinc-200 group-hover:bg-zinc-400 group-hover:dark:bg-zinc-200 !bg-opacity-40",
+ border: "border-zinc-500 dark:border-zinc-300",
+ borderHover: "hover:border-zinc-500 hover:dark:border-zinc-200",
+ featured: true,
+ category: "Plugin",
+ package: "plugin-eslint",
+ },
+ {
+ label: "Devtools",
+ description: "Devtools to help you debug your code",
+ dir: "plugin-devtools",
+ isPackage: true,
+ paths: ["plugin-devtools"],
+ img: HFIcon,
+ text: "drop-shadow-sm !text-yellow-500 dark:!text-yellow-300",
+ textAction:
+ "focus:!text-yellow-500 focus:dark:!text-yellow-300 active:!text-yellow-600 active:dark:!text-yellow-200",
+ textHover: "hover:!text-yellow-500 hover:dark:!text-yellow-400",
+ icon: "group-hover:shadow-yellow-200 dark:group-hover:bg-yellow-300 bg-yellow-400 dark:bg-yellow-300 !bg-opacity-30",
+ iconHover:
+ "group-hover:shadow-yellow-200 dark:group-hover:bg-yellow-200 group-hover:bg-yellow-400 group-hover:dark:bg-yellow-200 !bg-opacity-40",
+ border: "border-yellow-500 dark:border-yellow-300",
+ borderHover: "hover:border-yellow-500 hover:dark:border-yellow-200",
+ featured: true,
+ category: "Plugin",
+ package: "plugin-devtools",
+ },
+ {
+ label: "Axios",
+ description: "Adapter for Axios",
+ dir: "adapter-axios",
+ isPackage: true,
+ paths: ["adapter-axios"],
+ img: AxiosIcon,
+ text: "drop-shadow-sm !text-purple-500 dark:!text-purple-400",
+ textAction:
+ "focus:!text-purple-500 focus:dark:!text-purple-400 active:!text-purple-600 active:dark:!text-purple-300",
+ textHover: "hover:!text-purple-500 hover:dark:!text-purple-400",
+ icon: "group-hover:shadow-purple-200 dark:group-hover:bg-purple-500 bg-purple-400 dark:bg-purple-500",
+ iconHover:
+ "group-hover:shadow-purple-200 dark:group-hover:bg-purple-500 group-hover:bg-purple-400 group-hover:dark:bg-purple-500",
+ border: "border-purple-500 dark:border-purple-400",
+ borderHover: "hover:border-purple-500 hover:dark:border-purple-400",
+ category: "Adapter",
+ package: "axios",
+ },
+ {
+ label: "Graphql",
+ description: "Adapter for GraphQL",
+ dir: "adapter-graphql",
+ isPackage: true,
+ paths: ["adapter-graphql"],
+ img: GraphqlIcon,
+ text: "drop-shadow-sm !text-purple-500 dark:!text-pink-400",
+ textAction: "focus:!text-pink-500 focus:dark:!text-pink-400 active:!text-pink-600 active:dark:!text-pink-300",
+ textHover: "hover:!text-pink-500 hover:dark:!text-pink-400",
+ icon: "group-hover:shadow-pink-200 dark:group-hover:bg-pink-500 bg-pink-400 dark:bg-pink-500 !bg-opacity-30",
+ iconHover:
+ "group-hover:shadow-pink-200 dark:group-hover:bg-pink-500 group-hover:bg-pink-400 group-hover:dark:bg-pink-500 !bg-opacity-40",
+ border: "border-pink-500 dark:border-pink-400",
+ borderHover: "hover:border-pink-500 hover:dark:border-pink-400",
+ featured: true,
+ category: "Adapter",
+ package: "graphql",
+ },
+ {
+ label: "Firebase",
+ description: "Adapter for Firebase",
+ dir: "adapter-firebase",
+ isPackage: true,
+ paths: ["adapter-firebase"],
+ img: FirebaseIcon,
+ text: "drop-shadow-sm !text-orange-500 dark:!text-orange-400",
+ textAction:
+ "focus:!text-orange-500 focus:dark:!text-orange-400 active:!text-orange-600 active:dark:!text-orange-300",
+ textHover: "hover:!text-orange-500 hover:dark:!text-orange-400",
+ icon: "group-hover:shadow-orange-200 dark:group-hover:bg-orange-500 bg-orange-400 dark:bg-orange-500 !bg-opacity-30",
+ iconHover:
+ "group-hover:shadow-orange-200 dark:group-hover:bg-orange-500 group-hover:bg-orange-400 group-hover:dark:bg-orange-500 !bg-opacity-40",
+ border: "border-orange-500 dark:border-orange-400",
+ borderHover: "hover:border-orange-500 hover:dark:border-orange-400",
+ featured: true,
+ category: "Adapter",
+ package: "firebase",
+ },
+ {
+ label: "Firebase Admin",
+ description: "Adapter for Firebase Admin",
+ dir: "adapter-firebase-admin",
+ isPackage: true,
+ paths: ["adapter-firebase-admin"],
+ img: FirebaseIcon,
+ text: "drop-shadow-sm !text-red-500 dark:!text-red-400",
+ textAction: "focus:!text-red-500 focus:dark:!text-red-400 active:!text-red-600 active:dark:!text-red-300",
+ textHover: "hover:!text-red-500 hover:dark:!text-red-400",
+ icon: "group-hover:shadow-red-200 dark:group-hover:bg-red-500 bg-red-400 dark:bg-red-500 !bg-opacity-30",
+ iconHover:
+ "group-hover:shadow-red-200 dark:group-hover:bg-red-500 group-hover:bg-red-400 group-hover:dark:bg-red-500 !bg-opacity-40",
+ border: "border-red-500 dark:border-red-400",
+ borderHover: "hover:border-red-500 hover:dark:border-red-400",
+ category: "Adapter",
+ package: "firebase-admin",
+ },
+ {
+ label: "Codegen Openapi",
+ description: "Codegen for Openapi",
+ dir: "codegen-openapi",
+ isPackage: true,
+ paths: ["codegen-openapi"],
+ img: OpenApiIcon,
+ text: "drop-shadow-sm !text-lime-500 dark:!text-lime-400",
+ textAction: "focus:!text-lime-500 focus:dark:!text-lime-400 active:!text-lime-600 active:dark:!text-lime-300",
+ textHover: "hover:!text-lime-500 hover:dark:!text-lime-400",
+ icon: "group-hover:shadow-lime-200 dark:group-hover:bg-lime-500 bg-lime-400 dark:bg-lime-500 !bg-opacity-30",
+ iconHover:
+ "group-hover:shadow-lime-200 dark:group-hover:bg-lime-500 group-hover:bg-lime-400 group-hover:dark:bg-lime-500 !bg-opacity-40",
+ border: "border-lime-500 dark:border-lime-400",
+ borderHover: "hover:border-lime-500 hover:dark:border-lime-400",
+ featured: true,
+ category: "Codegen",
+ package: "codegen-openapi",
+ },
+];
diff --git a/documentation/src/lib/chart-utils.ts b/documentation/src/lib/chart-utils.ts
new file mode 100644
index 000000000..2c14eef09
--- /dev/null
+++ b/documentation/src/lib/chart-utils.ts
@@ -0,0 +1,97 @@
+// Tremor chartColors [v0.1.0]
+
+export type ColorUtility = "bg" | "stroke" | "fill" | "text";
+
+export const chartColors = {
+ blue: {
+ bg: "bg-blue-500",
+ stroke: "stroke-blue-500",
+ fill: "fill-blue-500",
+ text: "text-blue-500",
+ },
+ emerald: {
+ bg: "bg-emerald-500",
+ stroke: "stroke-emerald-500",
+ fill: "fill-emerald-500",
+ text: "text-emerald-500",
+ },
+ violet: {
+ bg: "bg-violet-500",
+ stroke: "stroke-violet-500",
+ fill: "fill-violet-500",
+ text: "text-violet-500",
+ },
+ amber: {
+ bg: "bg-amber-500",
+ stroke: "stroke-amber-500",
+ fill: "fill-amber-500",
+ text: "text-amber-500",
+ },
+ gray: {
+ bg: "bg-gray-500",
+ stroke: "stroke-gray-500",
+ fill: "fill-gray-500",
+ text: "text-gray-500",
+ },
+ cyan: {
+ bg: "bg-cyan-500",
+ stroke: "stroke-cyan-500",
+ fill: "fill-cyan-500",
+ text: "text-cyan-500",
+ },
+ pink: {
+ bg: "bg-pink-500",
+ stroke: "stroke-pink-500",
+ fill: "fill-pink-500",
+ text: "text-pink-500",
+ },
+ lime: {
+ bg: "bg-lime-500",
+ stroke: "stroke-lime-500",
+ fill: "fill-lime-500",
+ text: "text-lime-500",
+ },
+ fuchsia: {
+ bg: "bg-fuchsia-500",
+ stroke: "stroke-fuchsia-500",
+ fill: "fill-fuchsia-500",
+ text: "text-fuchsia-500",
+ },
+} as const satisfies {
+ [color: string]: {
+ [key in ColorUtility]: string;
+ };
+};
+
+export type AvailableChartColorsKeys = keyof typeof chartColors;
+
+export const AvailableChartColors: AvailableChartColorsKeys[] = Object.keys(
+ chartColors,
+) as Array;
+
+export const constructCategoryColors = (
+ categories: string[],
+ colors: AvailableChartColorsKeys[],
+): Map => {
+ const categoryColors = new Map();
+ categories.forEach((category, index) => {
+ categoryColors.set(category, colors[index % colors.length]);
+ });
+ return categoryColors;
+};
+
+export const getColorClassName = (color: AvailableChartColorsKeys, type: ColorUtility): string => {
+ const fallbackColor = {
+ bg: "bg-gray-500",
+ stroke: "stroke-gray-500",
+ fill: "fill-gray-500",
+ text: "text-gray-500",
+ };
+ return chartColors[color]?.[type] ?? fallbackColor[type];
+};
+
+export const getYAxisDomain = (autoMinValue: boolean, minValue: number | undefined, maxValue: number | undefined) => {
+ const minDomain = autoMinValue ? "auto" : (minValue ?? 0);
+ const maxDomain = maxValue ?? "auto";
+ return [minDomain, maxDomain];
+};
diff --git a/documentation/src/lib/utils.ts b/documentation/src/lib/utils.ts
new file mode 100644
index 000000000..a5ef19350
--- /dev/null
+++ b/documentation/src/lib/utils.ts
@@ -0,0 +1,6 @@
+import { clsx, type ClassValue } from "clsx";
+import { twMerge } from "tailwind-merge";
+
+export function cn(...inputs: ClassValue[]) {
+ return twMerge(clsx(inputs));
+}
diff --git a/documentation/src/modules.ts b/documentation/src/modules.ts
new file mode 100644
index 000000000..276c3da5e
--- /dev/null
+++ b/documentation/src/modules.ts
@@ -0,0 +1,147 @@
+/* eslint-disable @typescript-eslint/no-var-requires */
+import { ComponentType, SVGProps } from "react";
+import { Book, LucideProps } from "lucide-react";
+
+import { isBrowser } from "./utils/is-browser";
+
+const ReactIcon = isBrowser() ? require("../static/img/integration-react.svg").default : () => null;
+const HFIcon = isBrowser() ? require("../static/img/integration-hf.svg").default : () => null;
+const SocketsIcon = isBrowser() ? require("../static/img/integration-sockets.svg").default : () => null;
+const HyperFlowIcon = isBrowser() ? require("../static/img/hyper-flow.svg").default : () => null;
+
+export type Section = {
+ label: string;
+ description: string;
+ dir: string;
+ /**
+ * @important
+ * Names provides backwards compatibility with the old sidebars
+ * This way we can add more paths if we rename something
+ */
+ paths: string[];
+ img:
+ | React.ForwardRefExoticComponent & React.RefAttributes>
+ | ComponentType & { title?: string }>;
+ text: string;
+ textAction: string;
+ textHover: string;
+ icon: string;
+ iconHover: string;
+ border: string;
+ borderHover: string;
+ category: string;
+ featured?: boolean;
+ isPackage: boolean;
+ isNew?: boolean;
+ isPro?: boolean;
+} & (
+ | {
+ isPackage: false;
+ package?: string;
+ }
+ | {
+ isPackage: true;
+ package: string;
+ }
+);
+
+/**
+ * This sections list must support backward compatibility with the old sidebars and sections
+ * To extend it or change the order, you must update the paths or the order of these sections in the array
+ *
+ * @Example Matching of the sidebar and folders are done through the paths array, it should include the name of folder
+ */
+export const modules: Section[] = [
+ {
+ label: "Getting Started",
+ description: "Documentation for the library",
+ isPackage: false,
+ dir: "getting-started",
+ paths: ["getting-started"],
+ img: Book,
+ text: "drop-shadow-sm !text-yellow-500 dark:!text-yellow-400",
+ textAction:
+ "focus:!text-yellow-500 focus:dark:!text-yellow-400 active:!text-yellow-600 active:dark:!text-yellow-300",
+ textHover: "hover:!text-yellow-500 hover:dark:!text-yellow-400",
+ icon: "group-hover:shadow-yellow-200 dark:group-hover:bg-yellow-500 bg-yellow-400 dark:bg-yellow-500",
+ iconHover:
+ "group-hover:shadow-yellow-200 dark:group-hover:bg-yellow-500 group-hover:bg-yellow-400 group-hover:dark:bg-yellow-500",
+ border: "border-yellow-500 dark:border-yellow-400",
+ borderHover: "hover:border-yellow-500 hover:dark:border-yellow-400",
+ category: "docs",
+ },
+ {
+ label: "Core",
+ description: "Core package of the library containing the core functionality",
+ isPackage: true,
+ dir: "core",
+ paths: ["core"],
+ img: HFIcon,
+ text: "drop-shadow-sm !text-green-500 dark:!text-green-400",
+ textAction: "focus:!text-green-500 focus:dark:!text-green-400 active:!text-green-600 active:dark:!text-green-300",
+ textHover: "hover:!text-green-500 hover:dark:!text-green-400",
+ icon: "group-hover:shadow-green-200 dark:group-hover:bg-green-500 bg-green-400 dark:bg-green-500 !bg-opacity-30",
+ iconHover:
+ "group-hover:shadow-green-200 dark:group-hover:bg-green-500 group-hover:bg-green-400 group-hover:dark:bg-green-500 !bg-opacity-40",
+ border: "border-green-500 dark:border-green-400",
+ borderHover: "hover:border-green-500 hover:dark:border-green-400",
+ category: "Framework",
+ package: "core",
+ },
+ {
+ label: "Sockets",
+ description: "Sockets package of the library containing the socket functionality",
+ isPackage: true,
+ dir: "sockets",
+ paths: ["sockets"],
+ img: SocketsIcon,
+ text: "drop-shadow-sm !text-blue-500 dark:!text-blue-400",
+ textAction: "focus:!text-blue-500 focus:dark:!text-blue-400 active:!text-blue-600 active:dark:!text-blue-300",
+ textHover: "hover:!text-blue-500 hover:dark:!text-blue-400",
+ icon: "group-hover:shadow-blue-200 dark:group-hover:bg-blue-500 bg-blue-400 dark:bg-blue-500 !bg-opacity-30",
+ iconHover:
+ "group-hover:shadow-blue-200 dark:group-hover:bg-blue-500 group-hover:bg-blue-400 group-hover:dark:bg-blue-500 !bg-opacity-40",
+ border: "border-blue-500 dark:border-blue-400",
+ borderHover: "hover:border-blue-500 hover:dark:border-blue-400",
+ category: "Framework",
+ package: "sockets",
+ },
+ {
+ label: "React",
+ description: "React integration package of the library",
+ isPackage: true,
+ dir: "react",
+ paths: ["react"],
+ img: ReactIcon,
+ text: "drop-shadow-sm !text-sky-500 dark:!text-sky-400",
+ textAction: "focus:!text-sky-500 focus:dark:!text-sky-400 active:!text-sky-600 active:dark:!text-sky-300",
+ textHover: "hover:!text-sky-500 hover:dark:!text-sky-400",
+ icon: "group-hover:shadow-sky-200 dark:group-hover:bg-sky-500 bg-sky-400 dark:bg-sky-500 !bg-opacity-30",
+ iconHover:
+ "group-hover:shadow-sky-200 dark:group-hover:bg-sky-500 group-hover:bg-sky-400 group-hover:dark:bg-sky-500 !bg-opacity-40",
+ border: "border-sky-500 dark:border-sky-400",
+ borderHover: "hover:border-sky-500 hover:dark:border-sky-400",
+ category: "Framework",
+ package: "react",
+ },
+ {
+ label: "HyperFlow",
+ description: "Devtools for building, testing and debugging your API connections",
+ isPackage: false,
+ dir: "hyper-flow",
+ paths: ["hyper-flow"],
+ img: HyperFlowIcon,
+ text: "drop-shadow-sm !text-yellow-500 dark:!text-yellow-400",
+ textAction:
+ "focus:!text-yellow-500 focus:dark:!text-yellow-400 active:!text-yellow-600 active:dark:!text-yellow-300",
+ textHover: "hover:!text-yellow-500 hover:dark:!text-yellow-400",
+ icon: "group-hover:shadow-yellow-200 dark:group-hover:bg-yellow-500 bg-yellow-400 dark:bg-yellow-500 !bg-opacity-30",
+ iconHover:
+ "group-hover:shadow-yellow-200 dark:group-hover:bg-yellow-500 group-hover:bg-yellow-400 group-hover:dark:bg-yellow-500 !bg-opacity-40",
+ border: "border-yellow-500 dark:border-yellow-400",
+ borderHover: "hover:border-yellow-500 hover:dark:border-yellow-400",
+ category: "Framework",
+ package: "react",
+ isPro: true,
+ },
+];
diff --git a/documentation/src/pages/index.tsx b/documentation/src/pages/index.tsx
index 6c05135fa..1aa309b06 100644
--- a/documentation/src/pages/index.tsx
+++ b/documentation/src/pages/index.tsx
@@ -1,22 +1,4 @@
-import React from "react";
-import Layout from "@theme/Layout";
-import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
+import { Landing } from "../components/landing";
-import { Description, Features, Header, Promotion, Partners, Preview } from "../components";
-
-export default function Home(): JSX.Element {
- const { siteConfig } = useDocusaurusContext();
- const title = "Data Fetching, Offline First, Caching, Queueing";
- return (
-
-
-
-
-
-
-
-
-
-
- );
-}
+// eslint-disable-next-line import/no-default-export
+export default Landing;
diff --git a/documentation/src/theme/Admonition/Icon/Danger.tsx b/documentation/src/theme/Admonition/Icon/Danger.tsx
new file mode 100644
index 000000000..608a8154d
--- /dev/null
+++ b/documentation/src/theme/Admonition/Icon/Danger.tsx
@@ -0,0 +1,8 @@
+import React, { type ReactNode } from "react";
+import type { Props } from "@theme/Admonition/Icon/Danger";
+import { Flame } from "lucide-react";
+
+// eslint-disable-next-line import/no-default-export
+export default function AdmonitionIconDanger(props: Props): ReactNode {
+ return ;
+}
diff --git a/documentation/src/theme/Admonition/Icon/Info.tsx b/documentation/src/theme/Admonition/Icon/Info.tsx
new file mode 100644
index 000000000..b2797d84a
--- /dev/null
+++ b/documentation/src/theme/Admonition/Icon/Info.tsx
@@ -0,0 +1,8 @@
+import React, { type ReactNode } from "react";
+import type { Props } from "@theme/Admonition/Icon/Info";
+import { Info } from "lucide-react";
+
+// eslint-disable-next-line import/no-default-export
+export default function AdmonitionIconInfo(props: Props): ReactNode {
+ return ;
+}
diff --git a/documentation/src/theme/Admonition/Icon/Learn.tsx b/documentation/src/theme/Admonition/Icon/Learn.tsx
new file mode 100644
index 000000000..5ea5da6a5
--- /dev/null
+++ b/documentation/src/theme/Admonition/Icon/Learn.tsx
@@ -0,0 +1,8 @@
+import React, { type ReactNode } from "react";
+import type { Props } from "@theme/Admonition/Icon/Note";
+import { GraduationCap } from "lucide-react";
+
+// eslint-disable-next-line import/no-default-export
+export default function AdmonitionIconLearn(props: Props): ReactNode {
+ return ;
+}
diff --git a/documentation/src/theme/Admonition/Icon/Note.tsx b/documentation/src/theme/Admonition/Icon/Note.tsx
new file mode 100644
index 000000000..abf5e39e7
--- /dev/null
+++ b/documentation/src/theme/Admonition/Icon/Note.tsx
@@ -0,0 +1,8 @@
+import React, { type ReactNode } from "react";
+import type { Props } from "@theme/Admonition/Icon/Note";
+import { Book } from "lucide-react";
+
+// eslint-disable-next-line import/no-default-export
+export default function AdmonitionIconNote(props: Props): ReactNode {
+ return ;
+}
diff --git a/documentation/src/theme/Admonition/Icon/Success.tsx b/documentation/src/theme/Admonition/Icon/Success.tsx
new file mode 100644
index 000000000..d835119e1
--- /dev/null
+++ b/documentation/src/theme/Admonition/Icon/Success.tsx
@@ -0,0 +1,8 @@
+import React, { type ReactNode } from "react";
+import type { Props } from "@theme/Admonition/Icon/Tip";
+import { Medal } from "lucide-react";
+
+// eslint-disable-next-line import/no-default-export
+export default function AdmonitionIconSuccess(props: Props): ReactNode {
+ return ;
+}
diff --git a/documentation/src/theme/Admonition/Icon/Tip.tsx b/documentation/src/theme/Admonition/Icon/Tip.tsx
new file mode 100644
index 000000000..ccd740ced
--- /dev/null
+++ b/documentation/src/theme/Admonition/Icon/Tip.tsx
@@ -0,0 +1,8 @@
+import React, { type ReactNode } from "react";
+import type { Props } from "@theme/Admonition/Icon/Tip";
+import { Lightbulb } from "lucide-react";
+
+// eslint-disable-next-line import/no-default-export
+export default function AdmonitionIconTip(props: Props): ReactNode {
+ return ;
+}
diff --git a/documentation/src/theme/Admonition/Icon/Warning.tsx b/documentation/src/theme/Admonition/Icon/Warning.tsx
new file mode 100644
index 000000000..5e4430f74
--- /dev/null
+++ b/documentation/src/theme/Admonition/Icon/Warning.tsx
@@ -0,0 +1,8 @@
+import React, { type ReactNode } from "react";
+import type { Props } from "@theme/Admonition/Icon/Warning";
+import { TriangleAlert } from "lucide-react";
+
+// eslint-disable-next-line import/no-default-export
+export default function AdmonitionIconCaution(props: Props): ReactNode {
+ return ;
+}
diff --git a/documentation/src/theme/Admonition/Layout/index.tsx b/documentation/src/theme/Admonition/Layout/index.tsx
new file mode 100644
index 000000000..02b99e89c
--- /dev/null
+++ b/documentation/src/theme/Admonition/Layout/index.tsx
@@ -0,0 +1,49 @@
+import React, { type ReactNode } from "react";
+import clsx from "clsx";
+import { ThemeClassNames } from "@docusaurus/theme-common";
+import type { Props } from "@theme/Admonition/Layout";
+
+import styles from "./styles.module.css";
+
+function AdmonitionContainer({
+ type,
+ className,
+ children,
+}: Pick & { children: ReactNode }) {
+ return (
+
+ {children}
+
+ );
+}
+
+function AdmonitionHeading({ icon, title }: Pick) {
+ return (
+
+ {icon}
+ {title}
+
+ );
+}
+
+function AdmonitionContent({ children }: Pick) {
+ return children ? {children}
: null;
+}
+
+// eslint-disable-next-line import/no-default-export
+export default function AdmonitionLayout(props: Props): ReactNode {
+ const { type, icon, title, children, className } = props;
+ return (
+
+ {title || icon ? : null}
+ {children}
+
+ );
+}
diff --git a/documentation/src/theme/Admonition/Layout/styles.module.css b/documentation/src/theme/Admonition/Layout/styles.module.css
new file mode 100644
index 000000000..88df7e639
--- /dev/null
+++ b/documentation/src/theme/Admonition/Layout/styles.module.css
@@ -0,0 +1,35 @@
+.admonition {
+ margin-bottom: 1em;
+}
+
+.admonitionHeading {
+ font: var(--ifm-heading-font-weight) var(--ifm-h5-font-size) /
+ var(--ifm-heading-line-height) var(--ifm-heading-font-family);
+ text-transform: uppercase;
+}
+
+/* Heading alone without content (does not handle fragment content) */
+.admonitionHeading:not(:last-child) {
+ margin-bottom: 0.3rem;
+}
+
+.admonitionHeading code {
+ text-transform: none;
+}
+
+.admonitionIcon {
+ display: inline-block;
+ vertical-align: middle;
+ margin-right: 0.4em;
+}
+
+.admonitionIcon svg {
+ display: inline-block;
+ height: 1.6em;
+ width: 1.6em;
+ fill: var(--ifm-alert-foreground-color);
+}
+
+.admonitionContent > :last-child {
+ margin-bottom: 0;
+}
diff --git a/documentation/src/theme/Admonition/Type/Caution.tsx b/documentation/src/theme/Admonition/Type/Caution.tsx
new file mode 100644
index 000000000..2b4e7d187
--- /dev/null
+++ b/documentation/src/theme/Admonition/Type/Caution.tsx
@@ -0,0 +1,32 @@
+/* eslint-disable react/destructuring-assignment */
+import React, { type ReactNode } from "react";
+import clsx from "clsx";
+import Translate from "@docusaurus/Translate";
+import type { Props } from "@theme/Admonition/Type/Caution";
+import AdmonitionLayout from "@theme/Admonition/Layout";
+import IconWarning from "@theme/Admonition/Icon/Warning";
+
+const infimaClassName = "alert alert--warning";
+
+const defaultProps = {
+ icon: ,
+ title: (
+
+ caution
+
+ ),
+};
+
+// TODO remove before v4: Caution replaced by Warning
+// see https://github.com/facebook/docusaurus/issues/7558
+// eslint-disable-next-line import/no-default-export
+export default function AdmonitionTypeCaution(props: Props): ReactNode {
+ return (
+
+ {props.children}
+
+ );
+}
diff --git a/documentation/src/theme/Admonition/Type/Danger.tsx b/documentation/src/theme/Admonition/Type/Danger.tsx
new file mode 100644
index 000000000..49fe1f2a3
--- /dev/null
+++ b/documentation/src/theme/Admonition/Type/Danger.tsx
@@ -0,0 +1,27 @@
+/* eslint-disable react/destructuring-assignment */
+import React, { type ReactNode } from "react";
+import clsx from "clsx";
+import Translate from "@docusaurus/Translate";
+import type { Props } from "@theme/Admonition/Type/Danger";
+import AdmonitionLayout from "@theme/Admonition/Layout";
+import IconDanger from "@theme/Admonition/Icon/Danger";
+
+const infimaClassName = "alert alert--danger";
+
+const defaultProps = {
+ icon: ,
+ title: (
+
+ danger
+
+ ),
+};
+
+// eslint-disable-next-line import/no-default-export
+export default function AdmonitionTypeDanger(props: Props): ReactNode {
+ return (
+
+ {props.children}
+
+ );
+}
diff --git a/documentation/src/theme/Admonition/Type/Info.tsx b/documentation/src/theme/Admonition/Type/Info.tsx
new file mode 100644
index 000000000..d9b82f6d0
--- /dev/null
+++ b/documentation/src/theme/Admonition/Type/Info.tsx
@@ -0,0 +1,27 @@
+/* eslint-disable react/destructuring-assignment */
+import React, { type ReactNode } from "react";
+import clsx from "clsx";
+import Translate from "@docusaurus/Translate";
+import type { Props } from "@theme/Admonition/Type/Info";
+import AdmonitionLayout from "@theme/Admonition/Layout";
+import IconInfo from "@theme/Admonition/Icon/Info";
+
+const infimaClassName = "alert alert--info";
+
+const defaultProps = {
+ icon: ,
+ title: (
+
+ info
+
+ ),
+};
+
+// eslint-disable-next-line import/no-default-export
+export default function AdmonitionTypeInfo(props: Props): ReactNode {
+ return (
+
+ {props.children}
+
+ );
+}
diff --git a/documentation/src/theme/Admonition/Type/Learn.tsx b/documentation/src/theme/Admonition/Type/Learn.tsx
new file mode 100644
index 000000000..f99a3c7c1
--- /dev/null
+++ b/documentation/src/theme/Admonition/Type/Learn.tsx
@@ -0,0 +1,28 @@
+/* eslint-disable react/destructuring-assignment */
+import React, { type ReactNode } from "react";
+import clsx from "clsx";
+import Translate from "@docusaurus/Translate";
+import type { Props } from "@theme/Admonition/Type/Note";
+import AdmonitionLayout from "@theme/Admonition/Layout";
+
+import IconLearn from "../Icon/Learn";
+
+const infimaClassName = "alert alert--learn";
+
+const defaultProps = {
+ icon: ,
+ title: (
+
+ note
+
+ ),
+};
+
+// eslint-disable-next-line import/no-default-export
+export default function AdmonitionTypeLearn(props: Props): ReactNode {
+ return (
+
+ {props.children}
+
+ );
+}
diff --git a/documentation/src/theme/Admonition/Type/Note.tsx b/documentation/src/theme/Admonition/Type/Note.tsx
new file mode 100644
index 000000000..f465dd53f
--- /dev/null
+++ b/documentation/src/theme/Admonition/Type/Note.tsx
@@ -0,0 +1,27 @@
+/* eslint-disable react/destructuring-assignment */
+import React, { type ReactNode } from "react";
+import clsx from "clsx";
+import Translate from "@docusaurus/Translate";
+import type { Props } from "@theme/Admonition/Type/Note";
+import AdmonitionLayout from "@theme/Admonition/Layout";
+import IconNote from "@theme/Admonition/Icon/Note";
+
+const infimaClassName = "alert alert--secondary";
+
+const defaultProps = {
+ icon: ,
+ title: (
+
+ note
+
+ ),
+};
+
+// eslint-disable-next-line import/no-default-export
+export default function AdmonitionTypeNote(props: Props): ReactNode {
+ return (
+
+ {props.children}
+
+ );
+}
diff --git a/documentation/src/theme/Admonition/Type/Success.tsx b/documentation/src/theme/Admonition/Type/Success.tsx
new file mode 100644
index 000000000..100cc9290
--- /dev/null
+++ b/documentation/src/theme/Admonition/Type/Success.tsx
@@ -0,0 +1,28 @@
+/* eslint-disable react/destructuring-assignment */
+import React, { type ReactNode } from "react";
+import clsx from "clsx";
+import Translate from "@docusaurus/Translate";
+import type { Props } from "@theme/Admonition/Type/Tip";
+import AdmonitionLayout from "@theme/Admonition/Layout";
+
+import IconSuccess from "../Icon/Success";
+
+const infimaClassName = "alert alert--success";
+
+const defaultProps = {
+ icon: ,
+ title: (
+
+ tip
+
+ ),
+};
+
+// eslint-disable-next-line import/no-default-export
+export default function AdmonitionTypeSuccess(props: Props): ReactNode {
+ return (
+
+ {props.children}
+
+ );
+}
diff --git a/documentation/src/theme/Admonition/Type/Tip.tsx b/documentation/src/theme/Admonition/Type/Tip.tsx
new file mode 100644
index 000000000..23e61ca93
--- /dev/null
+++ b/documentation/src/theme/Admonition/Type/Tip.tsx
@@ -0,0 +1,27 @@
+/* eslint-disable react/destructuring-assignment */
+import React, { type ReactNode } from "react";
+import clsx from "clsx";
+import Translate from "@docusaurus/Translate";
+import type { Props } from "@theme/Admonition/Type/Tip";
+import AdmonitionLayout from "@theme/Admonition/Layout";
+import IconTip from "@theme/Admonition/Icon/Tip";
+
+const infimaClassName = "alert alert--tip";
+
+const defaultProps = {
+ icon: ,
+ title: (
+
+ tip
+
+ ),
+};
+
+// eslint-disable-next-line import/no-default-export
+export default function AdmonitionTypeTip(props: Props): ReactNode {
+ return (
+
+ {props.children}
+
+ );
+}
diff --git a/documentation/src/theme/Admonition/Type/Warning.tsx b/documentation/src/theme/Admonition/Type/Warning.tsx
new file mode 100644
index 000000000..4ea232cec
--- /dev/null
+++ b/documentation/src/theme/Admonition/Type/Warning.tsx
@@ -0,0 +1,30 @@
+/* eslint-disable react/destructuring-assignment */
+import React, { type ReactNode } from "react";
+import clsx from "clsx";
+import Translate from "@docusaurus/Translate";
+import type { Props } from "@theme/Admonition/Type/Warning";
+import AdmonitionLayout from "@theme/Admonition/Layout";
+import IconWarning from "@theme/Admonition/Icon/Warning";
+
+const infimaClassName = "alert alert--warning";
+
+const defaultProps = {
+ icon: ,
+ title: (
+
+ warning
+
+ ),
+};
+
+// eslint-disable-next-line import/no-default-export
+export default function AdmonitionTypeWarning(props: Props): ReactNode {
+ return (
+
+ {props.children}
+
+ );
+}
diff --git a/documentation/src/theme/Admonition/Types.tsx b/documentation/src/theme/Admonition/Types.tsx
new file mode 100644
index 000000000..7e43aa037
--- /dev/null
+++ b/documentation/src/theme/Admonition/Types.tsx
@@ -0,0 +1,35 @@
+import AdmonitionTypeNote from "@theme/Admonition/Type/Note";
+import AdmonitionTypeTip from "@theme/Admonition/Type/Tip";
+import AdmonitionTypeInfo from "@theme/Admonition/Type/Info";
+import AdmonitionTypeWarning from "@theme/Admonition/Type/Warning";
+import AdmonitionTypeDanger from "@theme/Admonition/Type/Danger";
+import AdmonitionTypeCaution from "@theme/Admonition/Type/Caution";
+import type AdmonitionTypes from "@theme/Admonition/Types";
+
+import AdmonitionTypeLearn from "./Type/Learn";
+import AdmonitionTypeSuccess from "./Type/Success";
+
+const admonitionTypes: typeof AdmonitionTypes = {
+ learn: AdmonitionTypeLearn,
+ note: AdmonitionTypeNote,
+ tip: AdmonitionTypeTip,
+ info: AdmonitionTypeInfo,
+ warning: AdmonitionTypeWarning,
+ danger: AdmonitionTypeDanger,
+};
+
+// Undocumented legacy admonition type aliases
+// Provide hardcoded/untranslated retrocompatible label
+// See also https://github.com/facebook/docusaurus/issues/7767
+const admonitionAliases: typeof AdmonitionTypes = {
+ secondary: AdmonitionTypeLearn,
+ important: AdmonitionTypeInfo,
+ success: AdmonitionTypeSuccess,
+ caution: AdmonitionTypeCaution,
+};
+
+// eslint-disable-next-line import/no-default-export
+export default {
+ ...admonitionTypes,
+ ...admonitionAliases,
+};
diff --git a/documentation/src/theme/Admonition/index.tsx b/documentation/src/theme/Admonition/index.tsx
new file mode 100644
index 000000000..17badd155
--- /dev/null
+++ b/documentation/src/theme/Admonition/index.tsx
@@ -0,0 +1,20 @@
+import React, { type ComponentType, type ReactNode } from "react";
+import { processAdmonitionProps } from "@docusaurus/theme-common";
+import type { Props } from "@theme/Admonition";
+import AdmonitionTypes from "@theme/Admonition/Types";
+
+function getAdmonitionTypeComponent(type: string): ComponentType {
+ const component = AdmonitionTypes[type];
+ if (component) {
+ return component;
+ }
+ console.warn(`No admonition component found for admonition type "${type}". Using Info as fallback.`);
+ return AdmonitionTypes.info!;
+}
+
+// eslint-disable-next-line import/no-default-export
+export default function Admonition(unprocessedProps: Props): ReactNode {
+ const props = processAdmonitionProps(unprocessedProps);
+ const AdmonitionTypeComponent = getAdmonitionTypeComponent(props.type);
+ return ;
+}
diff --git a/documentation/src/theme/BlogLayout/index.tsx b/documentation/src/theme/BlogLayout/index.tsx
new file mode 100644
index 000000000..35aace862
--- /dev/null
+++ b/documentation/src/theme/BlogLayout/index.tsx
@@ -0,0 +1,55 @@
+import React from "react";
+import clsx from "clsx";
+import Layout from "@theme/Layout";
+import BlogSidebar from "@theme/BlogSidebar";
+import type { Props } from "@theme/BlogLayout";
+import { Particles } from "@site/src/components";
+// import { Particles } from "@site/src/components";
+
+// eslint-disable-next-line import/no-default-export, @typescript-eslint/naming-convention
+export default function BlogLayout(props: Props): JSX.Element {
+ const { sidebar, toc, children, ...layoutProps } = props;
+ const hasSidebar = sidebar && sidebar.items.length > 0;
+
+ return (
+
+ {/* Particles animation */}
+
+
+ {/* Radial gradient */}
+
+
+ {/* Illustration */}
+
+
+
+
+ {/* Title */}
+
+
+
+
+ {children}
+
+ {toc &&
{toc}
}
+
+
+
+ );
+}
diff --git a/documentation/src/theme/CodeBlock/index.tsx b/documentation/src/theme/CodeBlock/index.tsx
new file mode 100644
index 000000000..801cbd556
--- /dev/null
+++ b/documentation/src/theme/CodeBlock/index.tsx
@@ -0,0 +1,39 @@
+import React, { useMemo, type ReactNode } from "react";
+import type { Props as CodeBlockProps } from "@theme/CodeBlock";
+import { parseCodeBlockTitle } from "@docusaurus/theme-common/internal";
+
+import OriginalCodeBlock from "../OriginalCodeBlock";
+import { LiveCodeBlock } from "./live-code-block";
+
+// TODO Docusaurus v4: remove special case
+// see packages/docusaurus-mdx-loader/src/remark/mdx1Compat/codeCompatPlugin.ts
+// we can just use the metastring instead
+declare module "@theme/CodeBlock" {
+ interface Props {
+ live?: boolean;
+ }
+}
+
+function isLiveCodeBlock(props: CodeBlockProps): boolean {
+ return !!props.live;
+}
+
+// eslint-disable-next-line import/no-default-export
+export default function CodeBlockEnhancer(props: CodeBlockProps): ReactNode {
+ const { metastring } = props;
+ const clickToRun = !metastring?.includes("autoPlay");
+ const defaultTab = metastring?.includes("console") ? "playground" : undefined;
+ const title = parseCodeBlockTitle(metastring);
+
+ const size = useMemo(() => {
+ if (metastring?.includes("size=md")) return "md";
+ if (metastring?.includes("size=lg")) return "lg";
+ return "sm";
+ }, [metastring]);
+
+ return isLiveCodeBlock(props) ? (
+
+ ) : (
+
+ );
+}
diff --git a/documentation/src/theme/CodeBlock/live-code-block/components/alert.tsx b/documentation/src/theme/CodeBlock/live-code-block/components/alert.tsx
new file mode 100644
index 000000000..bb3cdc8d3
--- /dev/null
+++ b/documentation/src/theme/CodeBlock/live-code-block/components/alert.tsx
@@ -0,0 +1,22 @@
+import React from "react";
+
+export const Alert = ({ children, ...props }) => (
+
+ {children}
+
+);
+
+export const AlertTitle = ({ children, ...props }) => (
+
+ {children}
+
+);
+
+export const AlertDescription = ({ children, ...props }) => (
+
+ {children}
+
+);
diff --git a/documentation/src/theme/CodeBlock/live-code-block/components/chip.tsx b/documentation/src/theme/CodeBlock/live-code-block/components/chip.tsx
new file mode 100644
index 000000000..70bd06e09
--- /dev/null
+++ b/documentation/src/theme/CodeBlock/live-code-block/components/chip.tsx
@@ -0,0 +1,10 @@
+import React from "react";
+
+export const Chip = ({ children, ...props }: React.HTMLProps) => (
+
+ {children}
+
+);
diff --git a/documentation/src/theme/CodeBlock/live-code-block/components/circular-progress.tsx b/documentation/src/theme/CodeBlock/live-code-block/components/circular-progress.tsx
new file mode 100644
index 000000000..a2e486558
--- /dev/null
+++ b/documentation/src/theme/CodeBlock/live-code-block/components/circular-progress.tsx
@@ -0,0 +1,9 @@
+import { cn } from "@site/src/lib/utils";
+import { Loader2 } from "lucide-react";
+import React from "react";
+
+export const CircularProgress = (props: React.HTMLProps) => (
+
+
+
+);
diff --git a/documentation/src/theme/CodeBlock/live-code-block/components/client-requests/client-requests.tsx b/documentation/src/theme/CodeBlock/live-code-block/components/client-requests/client-requests.tsx
new file mode 100644
index 000000000..145c6b1ef
--- /dev/null
+++ b/documentation/src/theme/CodeBlock/live-code-block/components/client-requests/client-requests.tsx
@@ -0,0 +1,17 @@
+import { ClientInstance } from "@hyper-fetch/core";
+import { Toaster } from "@site/src/components/ui/toast";
+
+import { OnlineWidget } from "../online-widget";
+import { Events } from "./components/events";
+
+export const ClientRequests = ({ client }: { client: ClientInstance }) => {
+ return (
+
+ );
+};
diff --git a/documentation/src/theme/CodeBlock/live-code-block/components/client-requests/components/app-event.tsx b/documentation/src/theme/CodeBlock/live-code-block/components/client-requests/components/app-event.tsx
new file mode 100644
index 000000000..062898f49
--- /dev/null
+++ b/documentation/src/theme/CodeBlock/live-code-block/components/client-requests/components/app-event.tsx
@@ -0,0 +1,32 @@
+import React from "react";
+import { Wifi, WifiOff, Eye, EyeOff } from "lucide-react";
+import { DocsCard } from "@site/src/components/ui/docs-card";
+
+import { EventType } from "./events";
+
+interface AppEventProps {
+ event: Extract;
+}
+
+const iconMap: Record = {
+ Online: ,
+ Offline: ,
+ "App window focused": ,
+ "App window blurred": ,
+};
+
+export const AppEvent: React.FC = ({ event }) => {
+ return (
+
+
+
+ {iconMap[event.name] || }
+
+
+ {event.name}
+ App Event
+
+
+
+ );
+};
diff --git a/documentation/src/theme/CodeBlock/live-code-block/components/client-requests/components/events.tsx b/documentation/src/theme/CodeBlock/live-code-block/components/client-requests/components/events.tsx
new file mode 100644
index 000000000..4320150b5
--- /dev/null
+++ b/documentation/src/theme/CodeBlock/live-code-block/components/client-requests/components/events.tsx
@@ -0,0 +1,262 @@
+/* eslint-disable react/no-array-index-key */
+import React, { useCallback, useEffect, useState } from "react";
+import { QueueRequest } from "@hyper-fetch/react";
+import { AnimatePresence } from "motion/react";
+import { AppWindowMac } from "lucide-react";
+import { ClientInstance, QueueDataType, QueueItemType, RequestInstance } from "@hyper-fetch/core";
+import { useToast } from "@site/src/hooks/use-toast";
+import { AnimatedListItem } from "@site/src/components/ui/animated-list-item";
+
+import { RequestEvent } from "./request-event";
+import { QueueEvent } from "./queue-event";
+import { AppEvent } from "./app-event";
+import { MessageEvent } from "./message-event";
+
+interface QueueProps {
+ client: ClientInstance;
+}
+
+export type EventType =
+ | {
+ type: "fetch-queue";
+ name: string;
+ timestamp: number;
+ }
+ | {
+ type: "submit-queue";
+ name: string;
+ timestamp: number;
+ }
+ | {
+ type: "app";
+ name: string;
+ timestamp: number;
+ }
+ | {
+ type: "request";
+ name: string;
+ timestamp: number;
+ };
+
+const canUpdate = (
+ item: Pick, "success" | "failed" | "canceled" | "removed" | "resolved">,
+) => {
+ if (item.success || (item.failed && !item.canceled)) {
+ return false;
+ }
+ return true;
+};
+
+export type ItemType = Omit<
+ QueueRequest,
+ "stopRequest" | "startRequest" | "deleteRequest" | "pauseRequest"
+>;
+
+export const Events: React.FC = ({ client }) => {
+ const [requests, setRequests] = useState([]);
+ const [stopped, setStopped] = useState>({});
+
+ const { toast } = useToast();
+
+ const createRequestsArray = useCallback(
+ (queueElements: QueueItemType[], prevRequests?: ItemType[]): ItemType[] => {
+ const newRequests = queueElements
+ // Keep only unique requests
+ .filter((el) => !prevRequests?.some((prevEl) => prevEl.requestId === el.requestId))
+ .map((req) => ({
+ failed: false,
+ canceled: false,
+ removed: false,
+ success: false,
+ ...req,
+ downloading: {
+ progress: 0,
+ timeLeft: 0,
+ sizeLeft: 0,
+ total: 0,
+ loaded: 0,
+ startTimestamp: 0,
+ },
+ uploading: {
+ progress: 0,
+ timeLeft: 0,
+ sizeLeft: 0,
+ total: 0,
+ loaded: 0,
+ startTimestamp: 0,
+ },
+ }));
+
+ return [...prevRequests, ...newRequests];
+ },
+ [],
+ );
+
+ const updateQueueState = useCallback(
+ (values: QueueDataType) => {
+ setStopped((prev) => ({ ...prev, [values.queryKey]: values.stopped }));
+ setRequests((prev) => createRequestsArray(values.requests, prev));
+ },
+ [createRequestsArray],
+ );
+
+ const mergePayloadType = useCallback((requestId: string, data: Partial) => {
+ setRequests((prev) =>
+ prev.map((el) => {
+ if (el.requestId === requestId && canUpdate(el)) {
+ return {
+ ...el,
+ ...data,
+ };
+ }
+
+ return el;
+ }),
+ );
+ }, []);
+
+ useEffect(() => {
+ const unmountFetch = client.fetchDispatcher.events.onQueueStatusChange((queue) => {
+ const timestamp = Date.now();
+ const hasRunningRequests = client.fetchDispatcher.hasRunningRequests(queue.queryKey);
+ const stoppedStatus = hasRunningRequests ? "Paused" : "Stopped";
+ const event = {
+ type: "fetch-queue",
+ name: queue.stopped ? stoppedStatus : "Running",
+ timestamp,
+ } as const;
+ toast({
+ message: ,
+ });
+ });
+ const unmountSubmit = client.submitDispatcher.events.onQueueStatusChange((queue) => {
+ const timestamp = Date.now();
+ const hasRunningRequests = client.submitDispatcher.hasRunningRequests(queue.queryKey);
+ const stoppedStatus = hasRunningRequests ? "Paused" : "Stopped";
+ const event = {
+ type: "fetch-queue",
+ name: queue.stopped ? stoppedStatus : "Running",
+ timestamp,
+ } as const;
+ toast({
+ message: ,
+ });
+ });
+
+ const unmountApp = client.appManager.events.onOnline(() => {
+ const event = {
+ type: "app",
+ name: "Online",
+ timestamp: Date.now(),
+ } as const;
+ toast({
+ message: ,
+ });
+ });
+
+ const unmountOffline = client.appManager.events.onOffline(() => {
+ const event = {
+ type: "app",
+ name: "Offline",
+ timestamp: Date.now(),
+ } as const;
+ toast({
+ message: ,
+ });
+ });
+
+ const unmountFetchChange = client.fetchDispatcher.events.onQueueChange(updateQueueState);
+ const unmountFetchStatus = client.fetchDispatcher.events.onQueueStatusChange(updateQueueState);
+ const unmountSubmitChange = client.submitDispatcher.events.onQueueChange(updateQueueState);
+ const unmountSubmitStatus = client.submitDispatcher.events.onQueueStatusChange(updateQueueState);
+
+ const unmountDeduplicated = client.requestManager.events.onDeduplicated(({ request }) => {
+ toast({
+ message: (
+
+ ),
+ });
+ });
+ const unmountStart = client.requestManager.events.onRequestStart(({ requestId }) => {
+ setRequests((prev) =>
+ prev.map((el) =>
+ el.requestId === requestId ? { ...el, failed: false, success: false, canceled: false, removed: false } : el,
+ ),
+ );
+ });
+ const unmountFailed = client.requestManager.events.onResponse(({ requestId, response, details }) => {
+ if (!response.success) {
+ setRequests((prev) =>
+ prev.map((el) => (el.requestId === requestId ? { ...el, failed: true, canceled: details.isCanceled } : el)),
+ );
+ } else {
+ setRequests((prev) => prev.map((el) => (el.requestId === requestId ? { ...el, success: true } : el)));
+ }
+ });
+
+ const unmountRemoved = client.requestManager.events.onRemove(({ requestId }) => {
+ setRequests((prev) =>
+ prev.map((el) => (el.requestId === requestId && canUpdate(el) ? { ...el, removed: true } : el)),
+ );
+ });
+
+ const unmountDownload = client.requestManager.events.onDownloadProgress(
+ ({ progress, timeLeft, sizeLeft, total, loaded, startTimestamp, requestId }) => {
+ mergePayloadType(requestId, { downloading: { progress, timeLeft, sizeLeft, total, loaded, startTimestamp } });
+ },
+ );
+
+ const unmountUpload = client.requestManager.events.onUploadProgress(
+ ({ progress, timeLeft, sizeLeft, total, loaded, startTimestamp, requestId }) => {
+ mergePayloadType(requestId, { uploading: { progress, timeLeft, sizeLeft, total, loaded, startTimestamp } });
+ },
+ );
+
+ return () => {
+ unmountDeduplicated();
+ unmountFetch();
+ unmountSubmit();
+ unmountApp();
+ unmountOffline();
+ unmountFetchStatus();
+ unmountFetchChange();
+ unmountSubmitStatus();
+ unmountSubmitChange();
+ unmountDownload();
+ unmountUpload();
+ unmountStart();
+ unmountFailed();
+ unmountRemoved();
+ };
+ }, [
+ client.fetchDispatcher,
+ client.submitDispatcher,
+ client.appManager,
+ client.requestManager.events,
+ updateQueueState,
+ mergePayloadType,
+ ]);
+
+ return (
+
+ {!requests.length && (
+
+ )}
+
+ {requests.map((event) => {
+ return (
+
+
+
+ );
+ })}
+
+
+ );
+};
diff --git a/documentation/src/theme/CodeBlock/live-code-block/components/client-requests/components/message-event.tsx b/documentation/src/theme/CodeBlock/live-code-block/components/client-requests/components/message-event.tsx
new file mode 100644
index 000000000..1e0ddb488
--- /dev/null
+++ b/documentation/src/theme/CodeBlock/live-code-block/components/client-requests/components/message-event.tsx
@@ -0,0 +1,40 @@
+import React from "react";
+import { AlertCircle, CheckCircle, MessageCircle } from "lucide-react";
+import { DocsCard } from "@site/src/components/ui/docs-card";
+import { cn } from "@site/src/lib/utils";
+
+interface MessageEventProps {
+ name: string;
+ message: string;
+ type?: "default" | "success" | "error";
+}
+
+const iconMap = {
+ default: MessageCircle,
+ success: CheckCircle,
+ error: AlertCircle,
+};
+
+const colorMap = {
+ default: "text-blue-500",
+ success: "text-green-500",
+ error: "text-red-500",
+};
+
+export const MessageEvent: React.FC = ({ name, message, type = "default" }) => {
+ const Icon = iconMap[type];
+ const color = colorMap[type];
+ return (
+
+
+
+