@kawaiininja/fetch 1.0.4 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +172 -0
  2. package/package.json +46 -46
package/README.md ADDED
@@ -0,0 +1,172 @@
1
+ # @kawaiininja/fetch
2
+
3
+ A production-grade, hybrid-native HTTP client designed for the Onyx Framework.
4
+
5
+ **Rating: S-Tier Utility 🏆**
6
+
7
+ This package automates enterprise-grade security, CSRF handling, and platform detection (Web vs. Native Mobile), allowing you to focus on building features rather than handling HTTP boilerplate.
8
+
9
+ ## 🚀 Features
10
+
11
+ - **Hybrid Intelligence**: Automatically detects if running on Web or Native Mobile (Capacitor).
12
+ - **Pro Security**:
13
+ - **Native**: Uses `SecureStoragePlugin` for token management.
14
+ - **Web**: Uses `HttpOnly` cookies + Auto-CSRF token rotation.
15
+ - **Smart Retries**: Automatically handles `403 CSRF` errors by fetching a new token and retrying the request.
16
+ - **Optimistic Updates**: Update your UI instantly before the server responds.
17
+ - **Type-Safe**: Full TypeScript support, but works efficiently in JS too.
18
+
19
+ ---
20
+
21
+ ## 🛠️ Setup
22
+
23
+ Wrap your application with the `ApiProvider` to configure your base URL and global behavior.
24
+
25
+ ```jsx
26
+ // src/App.jsx
27
+ import { ApiProvider } from "@kawaiininja/fetch";
28
+
29
+ const apiConfig = {
30
+ baseUrl: "https://api.myapp.com",
31
+ version: "v1",
32
+ // Optional: Global error handler (e.g., for Toast notifications)
33
+ onError: (msg, status) => console.error(`[API Error ${status}]: ${msg}`),
34
+ };
35
+
36
+ export default function App() {
37
+ return (
38
+ <ApiProvider config={apiConfig}>
39
+ <YourApp />
40
+ </ApiProvider>
41
+ );
42
+ }
43
+ ```
44
+
45
+ ---
46
+
47
+ ## 📖 Usage Patterns (Efficient JS)
48
+
49
+ ### 1. Lazy Action (Forms & Buttons)
50
+
51
+ Best for login forms, submitting data, or manual triggers. No need for `useState` or `try/catch` boilerplate.
52
+
53
+ ```jsx
54
+ import { useFetch } from "@kawaiininja/fetch";
55
+
56
+ export const LoginForm = () => {
57
+ // Extract helpers directly
58
+ const { post, isLoading, error } = useFetch("/auth/login");
59
+
60
+ const handleLogin = async (e) => {
61
+ e.preventDefault();
62
+ const formData = new FormData(e.target);
63
+ const payload = Object.fromEntries(formData);
64
+
65
+ // ✅ Efficient: helper handles JSON stringify, headers, and loading state
66
+ const user = await post(payload);
67
+
68
+ if (user) {
69
+ console.log("Welcome", user.name);
70
+ // Redirect or update context here
71
+ }
72
+ };
73
+
74
+ return (
75
+ <form onSubmit={handleLogin}>
76
+ {error && <div className="error-banner">{error}</div>}
77
+
78
+ <input name="email" type="email" placeholder="Email" />
79
+ <input name="password" type="password" placeholder="Password" />
80
+
81
+ <button disabled={isLoading}>
82
+ {isLoading ? "Logging in..." : "Log In"}
83
+ </button>
84
+ </form>
85
+ );
86
+ };
87
+ ```
88
+
89
+ ### 2. Optimistic Updates (Instant UX)
90
+
91
+ Make your app feel zero-latency by updating the local data _before_ the server responds.
92
+
93
+ ```jsx
94
+ const UserProfile = () => {
95
+ // 'data' is your state, 'setData' lets you modify it instantly
96
+ const { data, setData, patch } = useFetch("/user/me");
97
+
98
+ const updateName = async (newName) => {
99
+ // 1. Instant UI update (Optimistic)
100
+ // We assume it will succeed to make it feel snappy
101
+ setData((prev) => ({ ...prev, name: newName }));
102
+
103
+ // 2. Send request in background
104
+ // If it fails, the error state will update automatically and revert (if you handle it)
105
+ await patch({ name: newName });
106
+ };
107
+
108
+ return (
109
+ <div>
110
+ <h1>Hello, {data?.name || "Guest"}</h1>
111
+ <button onClick={() => updateName("Vinay")}>Update Name</button>
112
+ </div>
113
+ );
114
+ };
115
+ ```
116
+
117
+ ### 3. Fetch on Load (Page Data)
118
+
119
+ For standard "load data when page opens" behavior, simply pair with `useEffect`.
120
+
121
+ ```jsx
122
+ import { useEffect } from "react";
123
+ import { useFetch } from "@kawaiininja/fetch";
124
+
125
+ export const Dashboard = () => {
126
+ // 'get' is the trigger function
127
+ const { data, isLoading, get } = useFetch("/dashboard");
128
+
129
+ useEffect(() => {
130
+ // Trigger the fetch when component mounts
131
+ get();
132
+ }, []); // Empty array ensures it only runs once
133
+
134
+ if (isLoading) return <div>Loading...</div>;
135
+
136
+ return (
137
+ <div>
138
+ <h1>Dashboard Stats</h1>
139
+ <pre>{JSON.stringify(data, null, 2)}</pre>
140
+ </div>
141
+ );
142
+ };
143
+ ```
144
+
145
+ ### 4. Reactive Fetch (Search & Filters)
146
+
147
+ Trigger a fetch automatically whenever a variable changes (like a filter button or search bar).
148
+
149
+ ```jsx
150
+ import { useEffect, useState } from "react";
151
+ import { useFetch } from "@kawaiininja/fetch";
152
+
153
+ export const FilterList = () => {
154
+ const [filter, setFilter] = useState("all");
155
+ const [search, setSearch] = useState("");
156
+ const { data, get } = useFetch("/items");
157
+
158
+ // ✅ The "Watcher" Pattern
159
+ useEffect(() => {
160
+ // Overrides the URL with new params whenever dependencies change
161
+ get({ url: `/items?status=${filter}&q=${search}` });
162
+ }, [filter, search]); // 👈 DEPENDENCY ARRAY controls the trigger
163
+
164
+ return (
165
+ <div>
166
+ <button onClick={() => setFilter("active")}>Active</button>
167
+ <input onChange={(e) => setSearch(e.target.value)} />
168
+ <List items={data} />
169
+ </div>
170
+ );
171
+ };
172
+ ```
package/package.json CHANGED
@@ -1,46 +1,46 @@
1
- {
2
- "name": "@kawaiininja/fetch",
3
- "version": "1.0.4",
4
- "description": "Core fetch utility for Onyx Framework",
5
- "main": "dist/index.js",
6
- "types": "dist/index.d.ts",
7
- "module": "dist/index.js",
8
- "type": "module",
9
- "exports": {
10
- ".": "./dist/index.js"
11
- },
12
- "files": [
13
- "dist",
14
- "README.md"
15
- ],
16
- "scripts": {
17
- "build": "tsc"
18
- },
19
- "keywords": [
20
- "react",
21
- "fetch",
22
- "onyx",
23
- "kawaiininja",
24
- "http"
25
- ],
26
- "author": "Vinay (4kawaiininja)",
27
- "license": "MIT",
28
- "peerDependencies": {
29
- "react": "^18.0.0 || ^19.0.0",
30
- "react-dom": "^18.0.0 || ^19.0.0"
31
- },
32
- "publishConfig": {
33
- "access": "public"
34
- },
35
- "devDependencies": {
36
- "@types/react": "^19.2.7",
37
- "@types/react-dom": "^19.2.3",
38
- "typescript": "^5.7.0"
39
- },
40
- "dependencies": {
41
- "@capacitor-community/security-provider": "^7.0.0",
42
- "@capacitor-community/text-to-speech": "^6.1.0",
43
- "@capacitor/core": "^8.0.1",
44
- "capacitor-secure-storage-plugin": "^0.13.0"
45
- }
46
- }
1
+ {
2
+ "name": "@kawaiininja/fetch",
3
+ "version": "1.0.6",
4
+ "description": "Core fetch utility for Onyx Framework",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "module": "dist/index.js",
8
+ "type": "module",
9
+ "exports": {
10
+ ".": "./dist/index.js"
11
+ },
12
+ "files": [
13
+ "dist",
14
+ "README.md"
15
+ ],
16
+ "scripts": {
17
+ "build": "tsc"
18
+ },
19
+ "keywords": [
20
+ "react",
21
+ "fetch",
22
+ "onyx",
23
+ "kawaiininja",
24
+ "http"
25
+ ],
26
+ "author": "Tristan (4kawaiininja)",
27
+ "license": "MIT",
28
+ "peerDependencies": {
29
+ "react": "^18.0.0 || ^19.0.0",
30
+ "react-dom": "^18.0.0 || ^19.0.0"
31
+ },
32
+ "publishConfig": {
33
+ "access": "public"
34
+ },
35
+ "devDependencies": {
36
+ "@types/react": "^19.2.7",
37
+ "@types/react-dom": "^19.2.3",
38
+ "typescript": "^5.7.0"
39
+ },
40
+ "dependencies": {
41
+ "@capacitor-community/security-provider": "^7.0.0",
42
+ "@capacitor-community/text-to-speech": "^6.1.0",
43
+ "@capacitor/core": "^8.0.1",
44
+ "capacitor-secure-storage-plugin": "^0.13.0"
45
+ }
46
+ }