zustic 1.0.2 โ†’ 1.0.4

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.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  <div align="center">
2
2
 
3
- # ๐ŸŽฏ Zustic
3
+ # Zustic
4
4
 
5
5
  ### Lightweight State Management for Modern React Applications
6
6
 
@@ -17,28 +17,31 @@ A **fast, minimal state management solution** for React ecosystems. Works seamle
17
17
 
18
18
  ---
19
19
 
20
- ## โœจ Key Features
20
+ ## Key Features
21
21
 
22
22
  ### Core Features
23
- - **๐Ÿชถ Ultra-Lightweight** โ€” Only ~500B (gzipped) with zero dependencies
24
- - **โšก Simple API** โ€” One function (`create`) to manage all your state
25
- - **๐ŸŽฃ React Hooks** โ€” Native React hooks integration with automatic subscriptions
26
- - **๐Ÿ“ฑ Multi-Platform** โ€” React, React Native, Next.js, and modern frameworks
27
- - **๐Ÿ”„ Reactive Updates** โ€” Automatic re-renders with optimized batching
28
- - **๐Ÿ’พ TypeScript First** โ€” Full type safety with perfect type inference
29
- - **๐Ÿš€ Production Ready** โ€” Battle-tested in real applications
23
+ - **Ultra-Lightweight** โ€” Only ~500B (gzipped) with zero dependencies
24
+ - **Simple API** โ€” One function (`create`) to manage all your state
25
+ - **React Hooks** โ€” Native React hooks integration with automatic subscriptions
26
+ - **Multi-Platform** โ€” React, React Native, Next.js, and modern frameworks
27
+ - **Reactive Updates** โ€” Automatic re-renders with optimized batching
28
+ - **TypeScript First** โ€” Full type safety with perfect type inference
29
+ - **Production Ready** โ€” Battle-tested in real applications
30
30
 
31
31
  ### Advanced Capabilities
32
- - **๐Ÿงฉ Middleware System** โ€” Extend functionality with logging, persistence, validation, and more
33
- - **๐Ÿ“ก Direct State Access** โ€” `get()` function for reading state outside components
34
- - **๐ŸŽฏ Selective Subscriptions** โ€” Components only re-render when their data changes
35
- - **โš™๏ธ Fully Extensible** โ€” Build custom middleware for any use case
36
- - **๐Ÿงช Easy Testing** โ€” Simple to test stores with middleware and async operations
37
- - **๐Ÿ”— Framework Agnostic** โ€” Create middleware once, use everywhere
32
+ - **Store Middleware System** โ€” Extend state management with logging, persistence, validation, and more
33
+ - **Query System** โ€” Built-in API data fetching with automatic caching, mutations, and plugins
34
+ - **Automatic Caching** โ€” Smart cache management with configurable timeout
35
+ - **Direct State Access** โ€” `get()` function for reading state outside components
36
+ - **Selective Subscriptions** โ€” Components only re-render when their data changes
37
+ - **Fully Extensible** โ€” Build custom middleware and plugins for any use case
38
+ - **Easy Testing** โ€” Simple to test stores and API queries with middleware and async operations
39
+ - **Plugin System** โ€” Global hooks for authentication, logging, error handling
40
+ - **Framework Agnostic** โ€” Create middleware and plugins once, use everywhere
38
41
 
39
42
  ---
40
43
 
41
- ## ๐Ÿ“ฆ Installation
44
+ ## Installation
42
45
 
43
46
  Choose your favorite package manager:
44
47
 
@@ -55,13 +58,13 @@ pnpm add zustic
55
58
 
56
59
  ---
57
60
 
58
- ## ๐Ÿค” Why Zustic?
61
+ ## Why Zustic?
59
62
 
60
63
  ### Size & Performance
61
64
  | Metric | Zustic | Redux | Zustand | Context API |
62
65
  |--------|--------|-------|---------|-------------|
63
66
  | **Bundle Size** | ~500B | ~6KB | ~2KB | Built-in |
64
- | **Performance** | โšก Optimized | Good | โšก Optimized | โš ๏ธ Re-renders |
67
+ | **Performance** | Optimized | Good | Optimized | Re-renders |
65
68
  | **Dependencies** | 0 | 0 | 0 | 0 |
66
69
 
67
70
  ### Developer Experience
@@ -74,16 +77,18 @@ pnpm add zustic
74
77
 
75
78
  | Feature | Zustic | Redux | Zustand | Context API |
76
79
  |---------|--------|-------|---------|-------------|
77
- | Bundle Size | ~500B โœ… | ~6KB | ~2KB | 0B |
80
+ | Bundle Size | ~500B | ~6KB | ~2KB | 0B |
78
81
  | Learning Curve | โญ Easy | โญโญโญโญโญ Hard | โญโญ Easy | โญโญโญ Medium |
79
- | Boilerplate | Minimal โœ… | Massive | Minimal | Some |
80
- | TypeScript | Excellent โœ… | Good | Good | Good |
81
- | Middleware | Built-in โœ… | Required | Optional | โŒ No |
82
- | API Simplicity | Very Simple โœ… | Complex | Simple | Medium |
82
+ | Boilerplate | Minimal | Massive | Minimal | Some |
83
+ | TypeScript | Excellent | Good | Good | Good |
84
+ | Store Middleware | Built-in | Required | Optional | No |
85
+ | Query System | Built-in | Separate | Separate | No |
86
+ | Caching | Automatic | Optional | Optional | No |
87
+ | API Simplicity | Very Simple | Complex | Simple | Medium |
83
88
 
84
89
  ---
85
90
 
86
- ## ๐Ÿš€ Quick Start
91
+ ## Quick Start
87
92
 
88
93
  ### 1. Create Your Store
89
94
 
@@ -130,7 +135,7 @@ That's it! No providers, no boilerplate, just pure state management.
130
135
 
131
136
  ---
132
137
 
133
- ## ๐Ÿ“š Core Concepts
138
+ ## Core Concepts
134
139
 
135
140
  ### Create a Store
136
141
 
@@ -158,38 +163,10 @@ function Component() {
158
163
  return <div>{count}</div>;
159
164
  }
160
165
  ```
161
- <!--
162
- ### Reading State Outside Components
163
166
 
164
- ```typescript
165
- // In event handlers, callbacks, or services
166
- const currentState = useStore.get();
167
- console.log(currentState.count);
168
- ```
169
-
170
- ### Updating State
171
-
172
- ```typescript
173
- // Partial update
174
- useStore.set({ count: 5 });
175
-
176
- // Functional update with access to current state
177
- useStore.set((state) => ({
178
- count: state.count + 1
179
- }));
167
+ ## Store Middleware System
180
168
 
181
- // Async updates
182
- useStore.set(async (state) => ({
183
- data: await fetchData(),
184
- loading: false
185
- }));
186
- ``` -->
187
-
188
- ---
189
-
190
- ## ๐Ÿงฉ Middleware System
191
-
192
- Extend Zustic with powerful middleware for logging, persistence, validation, and more.
169
+ Extend Zustic stores with powerful middleware for logging, persistence, validation, and more.
193
170
 
194
171
  ### Logger Middleware
195
172
 
@@ -261,6 +238,302 @@ export const useStore = create<StoreType>(
261
238
 
262
239
  ---
263
240
 
241
+ ## Query System (API Data Fetching)
242
+
243
+ Zustic now includes a powerful query system for managing API requests with automatic caching, mutations, middleware, and plugins.
244
+
245
+ ### Create an API
246
+
247
+ ```typescript
248
+ import { createApi } from 'zustic/query';
249
+
250
+ type User = {
251
+ id: number;
252
+ name: string;
253
+ email: string;
254
+ };
255
+
256
+ const baseQuery = async (args: any) => {
257
+ try {
258
+
259
+ const response = await fetch(`https://api.example.com${args.url}`, {
260
+ method: args.method || 'GET',
261
+ headers: args.headers,
262
+ body: args.body ? JSON.stringify(args.body) : undefined,
263
+ });
264
+ const data = await response.json();
265
+ return { data };
266
+ } catch (error) {
267
+ return { error };
268
+ }
269
+ };
270
+
271
+ export const api = createApi({
272
+ baseQuery,
273
+ endpoints: (builder) => ({
274
+ getUsers: builder.query<User[], void>({
275
+ query: () => ({
276
+ url: '/users',
277
+ method: 'GET',
278
+ }),
279
+ transformResponse: (data) => data.map((u: User) => ({ ...u, name: u.name.toUpperCase() })),
280
+ }),
281
+
282
+ getUser: builder.query<User, { id: number }>({
283
+ query: ({ id }) => ({
284
+ url: `/users/${id}`,
285
+ method: 'GET',
286
+ }),
287
+ }),
288
+
289
+ createUser: builder.mutation<User, Omit<User, 'id'>>({
290
+ query: (body) => ({
291
+ url: '/users',
292
+ method: 'POST',
293
+ body,
294
+ }),
295
+ onSuccess: (data) => console.log('User created:', data),
296
+ onError: (error) => console.error('Failed to create:', error),
297
+ }),
298
+
299
+ updateUser: builder.mutation<User, Partial<User>>({
300
+ query: (body) => ({
301
+ url: `/users/${body.id}`,
302
+ method: 'PUT',
303
+ body,
304
+ }),
305
+ }),
306
+ }),
307
+ cacheTimeout: 5 * 60 * 1000, // 5 minutes
308
+ });
309
+ ```
310
+
311
+ ### Use Queries in Components
312
+
313
+ ```typescript
314
+ import { api } from './api';
315
+
316
+ function UsersList() {
317
+ // Query hook automatically fetches on mount
318
+ const { data: users, isLoading, isError, error, reFetch } = api.useUsersQuery();
319
+
320
+ if (isLoading) return <div>Loading...</div>;
321
+ if (isError) return <div>Error: {error?.message}</div>;
322
+
323
+ return (
324
+ <div>
325
+ <h2>Users</h2>
326
+ <button onClick={() => reFetch()}>Refresh</button>
327
+ <ul>
328
+ {users?.map((user) => (
329
+ <li key={user.id}>{user.name}</li>
330
+ ))}
331
+ </ul>
332
+ </div>
333
+ );
334
+ }
335
+ ```
336
+
337
+ ### Skip Queries (Conditional Fetching)
338
+
339
+ ```typescript
340
+ function UserDetail({ userId }: { userId?: number }) {
341
+ // Only fetch when userId is provided
342
+ const { data: user, isLoading } = api.useGetUserQuery(
343
+ { id: userId! },
344
+ { skip: !userId }
345
+ );
346
+
347
+ if (!userId) return <div>Select a user</div>;
348
+ if (isLoading) return <div>Loading...</div>;
349
+
350
+ return <div>{user?.name} ({user?.email})</div>;
351
+ }
352
+ ```
353
+
354
+ ### Use Mutations in Components
355
+
356
+ ```typescript
357
+ function CreateUserForm() {
358
+ // Mutation hook returns [mutate, state]
359
+ const [createUser, { isLoading, isError, error, data, isSuccess }] = api.useCreateUserMutation();
360
+
361
+ const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
362
+ e.preventDefault();
363
+ const formData = new FormData(e.currentTarget);
364
+
365
+ await createUser({
366
+ name: formData.get('name') as string,
367
+ email: formData.get('email') as string,
368
+ });
369
+ };
370
+
371
+ return (
372
+ <form onSubmit={handleSubmit}>
373
+ <input name="name" placeholder="Name" required />
374
+ <input name="email" type="email" placeholder="Email" required />
375
+ <button type="submit" disabled={isLoading}>
376
+ {isLoading ? 'Creating...' : 'Create User'}
377
+ </button>
378
+ {isSuccess && <p User created!</p>}
379
+ {isError && <p> Error: {error?.message}</p>}
380
+ </form>
381
+ );
382
+ }
383
+ ```
384
+
385
+ ### Query API Features
386
+
387
+ #### Transformations
388
+
389
+ ```typescript
390
+ getUser: builder.query<User, { id: number }>({
391
+ query: ({ id }) => ({
392
+ url: `/users/${id}`,
393
+ method: 'GET',
394
+ }),
395
+ // Transform the response data
396
+ transformResponse: (data) => ({
397
+ ...data,
398
+ formattedDate: new Date(data.createdAt).toLocaleDateString(),
399
+ }),
400
+ // Transform errors
401
+ transformError: (error) => ({
402
+ message: error.message || 'Unknown error occurred',
403
+ code: error.code,
404
+ }),
405
+ // Transform request body
406
+ transformBody: (body) => ({
407
+ ...body,
408
+ timestamp: Date.now(),
409
+ }),
410
+ // Transform request headers
411
+ transformHeader: (headers) => ({
412
+ ...headers,
413
+ 'Authorization': `Bearer ${getToken()}`,
414
+ }),
415
+ }),
416
+ ```
417
+
418
+ #### Hooks and Callbacks
419
+
420
+ ```typescript
421
+ createUser: builder.mutation<User, CreateUserInput>({
422
+ query: (body) => ({
423
+ url: '/users',
424
+ method: 'POST',
425
+ body,
426
+ }),
427
+ onSuccess: async (data) => {
428
+ console.log( 'User created:', data)
429
+ },
430
+ onError: async (error) => {
431
+ console.error(' Failed:', error)
432
+ },
433
+ }),
434
+ ```
435
+
436
+ #### Automatic Caching
437
+
438
+ ```typescript
439
+ const api = createApi({
440
+ baseQuery,
441
+ endpoints: (builder) => ({
442
+ getUser: builder.query<User, { id: number }>({
443
+ query: ({ id }) => ({
444
+ url: `/users/${id}`,
445
+ method: 'GET',
446
+ }),
447
+ }),
448
+ }),
449
+ cacheTimeout: 10 * 60 * 1000, // Cache for 10 minutes
450
+ });
451
+
452
+ // First call: fetches from API
453
+ const result1 = useGetUserQuery({ id: 1 });
454
+
455
+ // Second call (within cache timeout): uses cached data
456
+ const result2 = useGetUserQuery({ id: 1 });
457
+
458
+ // Force refetch
459
+ const result3 = await reFetch();
460
+ ```
461
+
462
+ #### Custom Query Function
463
+
464
+ ```typescript
465
+ getUserCustom: builder.query<User, { id: number }>({
466
+ queryFnc: async (arg, baseQuery) => {
467
+ // Implement custom logic
468
+ const token = localStorage.getItem('token');
469
+ return baseQuery({
470
+ url: `/users/${arg.id}`,
471
+ method: 'GET',
472
+ headers: { Authorization: `Bearer ${token}` },
473
+ });
474
+ },
475
+ }),
476
+ ```
477
+
478
+ ---
479
+
480
+ ## Query Middleware & Plugins
481
+
482
+ ### Query-Level Middleware
483
+
484
+ ```typescript
485
+ const requestLogger: ApiMiddleware = (ctx, next) => {
486
+ console.log('Request:', ctx.arg);
487
+ const result = await next();
488
+ console.log('Response:', result);
489
+ return result;
490
+ };
491
+
492
+ getUser: builder.query<User, { id: number }>({
493
+ query: ({ id }) => ({
494
+ url: `/users/${id}`,
495
+ method: 'GET',
496
+ }),
497
+ middlewares: [requestLogger],
498
+ }),
499
+ ```
500
+
501
+ ### Global Plugins
502
+
503
+ ```typescript
504
+ const authPlugin: ApiPlugin = {
505
+ name: 'auth-plugin',
506
+
507
+ beforeQuery: (ctx) => {
508
+ const token = localStorage.getItem('token');
509
+ if (!token) {
510
+ throw new Error('Not authenticated');
511
+ }
512
+ },
513
+
514
+ afterQuery: (result, ctx) => {
515
+ if (result.error?.status === 401) {
516
+ // Handle unauthorized
517
+ window.location.href = '/login';
518
+ }
519
+ },
520
+
521
+ onError: (error, ctx) => {
522
+ console.error('API Error:', error);
523
+ },
524
+ };
525
+
526
+ const api = createApi({
527
+ baseQuery,
528
+ endpoints: (builder) => ({
529
+ // endpoints...
530
+ }),
531
+ plugins: [authPlugin],
532
+ });
533
+ ```
534
+
535
+ ---
536
+
264
537
  ## ๐Ÿ“ฑ Multi-Platform Examples
265
538
 
266
539
  ### React Web
@@ -331,7 +604,7 @@ export default function Page() {
331
604
 
332
605
  ---
333
606
 
334
- ## ๐Ÿงช Testing
607
+ ## Testing
335
608
 
336
609
  Zustic stores are easy to test:
337
610
 
@@ -363,7 +636,7 @@ describe('Counter Store', () => {
363
636
 
364
637
  ---
365
638
 
366
- ## ๐Ÿ’ก Advanced Examples
639
+ ## Advanced Examples
367
640
 
368
641
  ### Async State
369
642
 
@@ -419,7 +692,7 @@ const useAppStore = create((set) => ({
419
692
 
420
693
  ---
421
694
 
422
- ## ๐Ÿ”— Resources
695
+ ## Resources
423
696
 
424
697
  - ๐Ÿ“– **[Full Documentation](https://zustic.github.io/)** - Complete API reference and guides
425
698
  - ๐Ÿ› **[GitHub Issues](https://github.com/DeveloperRejaul/zustic/issues)** - Report bugs and request features
@@ -428,7 +701,7 @@ const useAppStore = create((set) => ({
428
701
 
429
702
  ---
430
703
 
431
- ## ๐Ÿ“ API Reference
704
+ ## API Reference
432
705
 
433
706
  ### `create<T>(initializer, middlewares?)`
434
707
 
@@ -452,19 +725,19 @@ const useStore = create((set, get) => ({
452
725
 
453
726
  ---
454
727
 
455
- ## ๐Ÿค Contributing
728
+ ## Contributing
456
729
 
457
730
  Contributions are welcome! Please feel free to submit a Pull Request to the [GitHub repository](https://github.com/DeveloperRejaul/zustic).
458
731
 
459
732
  ---
460
733
 
461
- ## ๐Ÿ“„ License
734
+ ## License
462
735
 
463
736
  MIT License ยฉ 2024 [Rejaul Karim](https://github.com/DeveloperRejaul)
464
737
 
465
738
  ---
466
739
 
467
- ## ๐Ÿ‘จโ€๐Ÿ’ป Author
740
+ ## Author
468
741
 
469
742
  Created by **Rejaul Karim** - [GitHub](https://github.com/DeveloperRejaul)
470
743
 
@@ -0,0 +1 @@
1
+ import{useSyncExternalStore as p}from"react";function d(a,n=[]){let e,t=[],s=r=>{let o=typeof r=="function"?r(e):r;e={...e,...o},t.forEach(T=>T())},i=()=>e,c=l(s,i,n);e=a(c,i);let S=r=>(t.push(r),()=>{t=t.filter(o=>o!==r)});return()=>p(S,i)}var l=(a,n,e)=>!e||e.length===0?a:e.reduceRight((t,s)=>s(a,n)(t),a);export{d as a};
package/dist/index.js CHANGED
@@ -1,73 +1 @@
1
- "use strict";
2
- "use client";
3
- var __defProp = Object.defineProperty;
4
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getOwnPropSymbols = Object.getOwnPropertySymbols;
7
- var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __propIsEnum = Object.prototype.propertyIsEnumerable;
9
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
10
- var __spreadValues = (a, b) => {
11
- for (var prop in b || (b = {}))
12
- if (__hasOwnProp.call(b, prop))
13
- __defNormalProp(a, prop, b[prop]);
14
- if (__getOwnPropSymbols)
15
- for (var prop of __getOwnPropSymbols(b)) {
16
- if (__propIsEnum.call(b, prop))
17
- __defNormalProp(a, prop, b[prop]);
18
- }
19
- return a;
20
- };
21
- var __export = (target, all) => {
22
- for (var name in all)
23
- __defProp(target, name, { get: all[name], enumerable: true });
24
- };
25
- var __copyProps = (to, from, except, desc) => {
26
- if (from && typeof from === "object" || typeof from === "function") {
27
- for (let key of __getOwnPropNames(from))
28
- if (!__hasOwnProp.call(to, key) && key !== except)
29
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
30
- }
31
- return to;
32
- };
33
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
34
-
35
- // src/index.ts
36
- var index_exports = {};
37
- __export(index_exports, {
38
- create: () => create
39
- });
40
- module.exports = __toCommonJS(index_exports);
41
- var import_react = require("react");
42
- function create(initializer, middlewares = []) {
43
- let state;
44
- let listeners = [];
45
- const setState = (partial) => {
46
- const partialState = typeof partial === "function" ? partial(state) : partial;
47
- state = __spreadValues(__spreadValues({}, state), partialState);
48
- listeners.forEach((l) => l());
49
- };
50
- const getState = () => state;
51
- const setStateWithMiddleware = applyMiddleware(setState, getState, middlewares);
52
- state = initializer(setStateWithMiddleware, getState);
53
- const subscribe = (listener) => {
54
- listeners.push(listener);
55
- return () => {
56
- listeners = listeners.filter((l) => l !== listener);
57
- };
58
- };
59
- return () => (0, import_react.useSyncExternalStore)(subscribe, getState);
60
- }
61
- var applyMiddleware = (set, get, middlewares) => {
62
- if (!middlewares || middlewares.length === 0) {
63
- return set;
64
- }
65
- return middlewares.reduceRight(
66
- (next, mw) => mw(set, get)(next),
67
- set
68
- );
69
- };
70
- // Annotate the CommonJS export names for ESM import in node:
71
- 0 && (module.exports = {
72
- create
73
- });
1
+ "use strict";var c=Object.defineProperty;var u=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var m=Object.prototype.hasOwnProperty;var y=(t,r)=>{for(var e in r)c(t,e,{get:r[e],enumerable:!0})},M=(t,r,e,a)=>{if(r&&typeof r=="object"||typeof r=="function")for(let o of f(r))!m.call(t,o)&&o!==e&&c(t,o,{get:()=>r[o],enumerable:!(a=u(r,o))||a.enumerable});return t};var P=t=>M(c({},"__esModule",{value:!0}),t);var x={};y(x,{create:()=>S});module.exports=P(x);var p=require("react");function S(t,r=[]){let e,a=[],o=s=>{let i=typeof s=="function"?s(e):s;e={...e,...i},a.forEach(l=>l())},n=()=>e,T=h(o,n,r);e=t(T,n);let d=s=>(a.push(s),()=>{a=a.filter(i=>i!==s)});return()=>(0,p.useSyncExternalStore)(d,n)}var h=(t,r,e)=>!e||e.length===0?t:e.reduceRight((a,o)=>o(t,r)(a),t);0&&(module.exports={create});
package/dist/index.mjs CHANGED
@@ -1,51 +1 @@
1
- "use client";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropSymbols = Object.getOwnPropertySymbols;
4
- var __hasOwnProp = Object.prototype.hasOwnProperty;
5
- var __propIsEnum = Object.prototype.propertyIsEnumerable;
6
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
7
- var __spreadValues = (a, b) => {
8
- for (var prop in b || (b = {}))
9
- if (__hasOwnProp.call(b, prop))
10
- __defNormalProp(a, prop, b[prop]);
11
- if (__getOwnPropSymbols)
12
- for (var prop of __getOwnPropSymbols(b)) {
13
- if (__propIsEnum.call(b, prop))
14
- __defNormalProp(a, prop, b[prop]);
15
- }
16
- return a;
17
- };
18
-
19
- // src/index.ts
20
- import { useSyncExternalStore } from "react";
21
- function create(initializer, middlewares = []) {
22
- let state;
23
- let listeners = [];
24
- const setState = (partial) => {
25
- const partialState = typeof partial === "function" ? partial(state) : partial;
26
- state = __spreadValues(__spreadValues({}, state), partialState);
27
- listeners.forEach((l) => l());
28
- };
29
- const getState = () => state;
30
- const setStateWithMiddleware = applyMiddleware(setState, getState, middlewares);
31
- state = initializer(setStateWithMiddleware, getState);
32
- const subscribe = (listener) => {
33
- listeners.push(listener);
34
- return () => {
35
- listeners = listeners.filter((l) => l !== listener);
36
- };
37
- };
38
- return () => useSyncExternalStore(subscribe, getState);
39
- }
40
- var applyMiddleware = (set, get, middlewares) => {
41
- if (!middlewares || middlewares.length === 0) {
42
- return set;
43
- }
44
- return middlewares.reduceRight(
45
- (next, mw) => mw(set, get)(next),
46
- set
47
- );
48
- };
49
- export {
50
- create
51
- };
1
+ import{a as e}from"./chunk-SISWF3T4.mjs";export{e as create};
@@ -0,0 +1,116 @@
1
+ type QueryFnObj = {
2
+ url: string;
3
+ method: "GET" | "POST" | "PUT" | "DELETE" | "PATCH";
4
+ body?: any;
5
+ headers?: Record<string, any>;
6
+ };
7
+ type QueryFnReturn = string | QueryFnObj;
8
+ type QueryFn<Arg = any> = (arg: Arg) => QueryFnReturn;
9
+ type MainQueryReturnTypes = Promise<{
10
+ data: any;
11
+ error?: undefined;
12
+ } | {
13
+ error: any;
14
+ data?: undefined;
15
+ }>;
16
+ type ApiOption<Arg, R> = {
17
+ transformResponse?: (currData: any, preData: any) => Promise<R> | R;
18
+ transformError?: (currError: any, preError: any) => Promise<any> | any;
19
+ transformBody?: (body: Arg) => Promise<any> | any;
20
+ transformHeader?: (header: Record<string, any>) => Promise<Record<string, any>> | Record<string, any>;
21
+ onError?: (err: any) => Promise<void> | void;
22
+ onSuccess?: (data: R) => Promise<void> | void;
23
+ queryFnc?: (arg: Arg, baseQuery: CreateApiParams<any>['baseQuery']) => MainQueryReturnTypes;
24
+ middlewares?: ApiMiddleware[];
25
+ plugins?: ApiPlugin[];
26
+ };
27
+ type QueryDef<Arg, Result> = {
28
+ type: 'query';
29
+ queryFn?: QueryFn<Arg>;
30
+ } & ApiOption<Arg, Result>;
31
+ type MutationDef<Arg, Result> = {
32
+ type: 'mutation';
33
+ queryFn?: QueryFn<Arg>;
34
+ } & ApiOption<Arg, Result>;
35
+ type EndpointDef = QueryDef<any, any> | MutationDef<any, any>;
36
+ type MainQueryHookResult<Result> = {
37
+ data?: Result;
38
+ isLoading: boolean;
39
+ isError: boolean;
40
+ isFetching: boolean;
41
+ isSuccess: boolean;
42
+ error: any;
43
+ reFetch: () => MainQueryReturnTypes;
44
+ };
45
+ type MainMutationState<Result> = {
46
+ data?: Result;
47
+ isLoading: boolean;
48
+ isError: boolean;
49
+ isSuccess: boolean;
50
+ error: any;
51
+ };
52
+ type EndpointsMap = Record<string, EndpointDef>;
53
+ type HooksFromEndpoints<T extends EndpointsMap> = {
54
+ [K in keyof T as T[K] extends {
55
+ type: 'query';
56
+ } ? `use${Capitalize<string & K>}Query` : `use${Capitalize<string & K>}Mutation`]: T[K] extends QueryDef<infer Arg, infer Result> ? (arg: Arg, option?: QueryHookOption) => MainQueryHookResult<Result> : T[K] extends MutationDef<infer Arg, infer Result> ? () => readonly [(arg: Arg) => Promise<Result>, MainMutationState<Result>] : never;
57
+ };
58
+ type BuilderType = {
59
+ query<Result, Arg = void>(config: {
60
+ query?: (arg: Arg) => QueryFnReturn;
61
+ } & ApiOption<Arg, Result>): QueryDef<Arg, Result>;
62
+ mutation<Result, Arg = void>(config: {
63
+ query?: (arg: Arg) => QueryFnObj;
64
+ } & ApiOption<Arg, Result>): MutationDef<Arg, Result>;
65
+ };
66
+ type BaseQueryReturn<Data = any, Error = any> = {
67
+ data: Data;
68
+ error?: undefined;
69
+ } | {
70
+ data?: undefined;
71
+ error: Error;
72
+ };
73
+ interface CreateApiParams<T extends EndpointsMap> {
74
+ baseQuery: (option: QueryFnReturn) => Promise<BaseQueryReturn>;
75
+ endpoints: (builder: BuilderType) => T;
76
+ cacheTimeout?: number;
77
+ middlewares?: ApiMiddleware[];
78
+ plugins?: ApiPlugin[];
79
+ }
80
+ interface QueryHookOption {
81
+ skip: boolean;
82
+ }
83
+ type MiddlewareContext = {
84
+ arg: any;
85
+ def: any;
86
+ get: any;
87
+ set: any;
88
+ };
89
+ type ApiMiddleware = (ctx: MiddlewareContext, next: () => Promise<{
90
+ data?: any;
91
+ error?: any;
92
+ }>) => Promise<{
93
+ data?: any;
94
+ error?: any;
95
+ }>;
96
+ type ApiPlugin = {
97
+ name: string;
98
+ onInit?: (api: {
99
+ baseQuery: any;
100
+ endpoints: any;
101
+ }) => void;
102
+ beforeQuery?: (ctx: PluginContext) => void | Promise<void>;
103
+ middleware?: ApiMiddleware;
104
+ afterQuery?: (result: any, ctx: PluginContext) => void | Promise<void>;
105
+ onError?: (error: any, ctx: PluginContext) => void | Promise<void>;
106
+ };
107
+ type PluginContext = {
108
+ arg: any;
109
+ def: any;
110
+ get: any;
111
+ set: any;
112
+ };
113
+
114
+ declare function createApi<T extends EndpointsMap>(params: CreateApiParams<T>): HooksFromEndpoints<T>;
115
+
116
+ export { type ApiMiddleware, type ApiPlugin, createApi };
@@ -0,0 +1,116 @@
1
+ type QueryFnObj = {
2
+ url: string;
3
+ method: "GET" | "POST" | "PUT" | "DELETE" | "PATCH";
4
+ body?: any;
5
+ headers?: Record<string, any>;
6
+ };
7
+ type QueryFnReturn = string | QueryFnObj;
8
+ type QueryFn<Arg = any> = (arg: Arg) => QueryFnReturn;
9
+ type MainQueryReturnTypes = Promise<{
10
+ data: any;
11
+ error?: undefined;
12
+ } | {
13
+ error: any;
14
+ data?: undefined;
15
+ }>;
16
+ type ApiOption<Arg, R> = {
17
+ transformResponse?: (currData: any, preData: any) => Promise<R> | R;
18
+ transformError?: (currError: any, preError: any) => Promise<any> | any;
19
+ transformBody?: (body: Arg) => Promise<any> | any;
20
+ transformHeader?: (header: Record<string, any>) => Promise<Record<string, any>> | Record<string, any>;
21
+ onError?: (err: any) => Promise<void> | void;
22
+ onSuccess?: (data: R) => Promise<void> | void;
23
+ queryFnc?: (arg: Arg, baseQuery: CreateApiParams<any>['baseQuery']) => MainQueryReturnTypes;
24
+ middlewares?: ApiMiddleware[];
25
+ plugins?: ApiPlugin[];
26
+ };
27
+ type QueryDef<Arg, Result> = {
28
+ type: 'query';
29
+ queryFn?: QueryFn<Arg>;
30
+ } & ApiOption<Arg, Result>;
31
+ type MutationDef<Arg, Result> = {
32
+ type: 'mutation';
33
+ queryFn?: QueryFn<Arg>;
34
+ } & ApiOption<Arg, Result>;
35
+ type EndpointDef = QueryDef<any, any> | MutationDef<any, any>;
36
+ type MainQueryHookResult<Result> = {
37
+ data?: Result;
38
+ isLoading: boolean;
39
+ isError: boolean;
40
+ isFetching: boolean;
41
+ isSuccess: boolean;
42
+ error: any;
43
+ reFetch: () => MainQueryReturnTypes;
44
+ };
45
+ type MainMutationState<Result> = {
46
+ data?: Result;
47
+ isLoading: boolean;
48
+ isError: boolean;
49
+ isSuccess: boolean;
50
+ error: any;
51
+ };
52
+ type EndpointsMap = Record<string, EndpointDef>;
53
+ type HooksFromEndpoints<T extends EndpointsMap> = {
54
+ [K in keyof T as T[K] extends {
55
+ type: 'query';
56
+ } ? `use${Capitalize<string & K>}Query` : `use${Capitalize<string & K>}Mutation`]: T[K] extends QueryDef<infer Arg, infer Result> ? (arg: Arg, option?: QueryHookOption) => MainQueryHookResult<Result> : T[K] extends MutationDef<infer Arg, infer Result> ? () => readonly [(arg: Arg) => Promise<Result>, MainMutationState<Result>] : never;
57
+ };
58
+ type BuilderType = {
59
+ query<Result, Arg = void>(config: {
60
+ query?: (arg: Arg) => QueryFnReturn;
61
+ } & ApiOption<Arg, Result>): QueryDef<Arg, Result>;
62
+ mutation<Result, Arg = void>(config: {
63
+ query?: (arg: Arg) => QueryFnObj;
64
+ } & ApiOption<Arg, Result>): MutationDef<Arg, Result>;
65
+ };
66
+ type BaseQueryReturn<Data = any, Error = any> = {
67
+ data: Data;
68
+ error?: undefined;
69
+ } | {
70
+ data?: undefined;
71
+ error: Error;
72
+ };
73
+ interface CreateApiParams<T extends EndpointsMap> {
74
+ baseQuery: (option: QueryFnReturn) => Promise<BaseQueryReturn>;
75
+ endpoints: (builder: BuilderType) => T;
76
+ cacheTimeout?: number;
77
+ middlewares?: ApiMiddleware[];
78
+ plugins?: ApiPlugin[];
79
+ }
80
+ interface QueryHookOption {
81
+ skip: boolean;
82
+ }
83
+ type MiddlewareContext = {
84
+ arg: any;
85
+ def: any;
86
+ get: any;
87
+ set: any;
88
+ };
89
+ type ApiMiddleware = (ctx: MiddlewareContext, next: () => Promise<{
90
+ data?: any;
91
+ error?: any;
92
+ }>) => Promise<{
93
+ data?: any;
94
+ error?: any;
95
+ }>;
96
+ type ApiPlugin = {
97
+ name: string;
98
+ onInit?: (api: {
99
+ baseQuery: any;
100
+ endpoints: any;
101
+ }) => void;
102
+ beforeQuery?: (ctx: PluginContext) => void | Promise<void>;
103
+ middleware?: ApiMiddleware;
104
+ afterQuery?: (result: any, ctx: PluginContext) => void | Promise<void>;
105
+ onError?: (error: any, ctx: PluginContext) => void | Promise<void>;
106
+ };
107
+ type PluginContext = {
108
+ arg: any;
109
+ def: any;
110
+ get: any;
111
+ set: any;
112
+ };
113
+
114
+ declare function createApi<T extends EndpointsMap>(params: CreateApiParams<T>): HooksFromEndpoints<T>;
115
+
116
+ export { type ApiMiddleware, type ApiPlugin, createApi };
@@ -0,0 +1 @@
1
+ "use strict";var q=Object.defineProperty;var k=Object.getOwnPropertyDescriptor;var H=Object.getOwnPropertyNames;var C=Object.prototype.hasOwnProperty;var R=(e,n)=>{for(var i in n)q(e,i,{get:n[i],enumerable:!0})},O=(e,n,i,r)=>{if(n&&typeof n=="object"||typeof n=="function")for(let c of H(n))!C.call(e,c)&&c!==i&&q(e,c,{get:()=>n[c],enumerable:!(r=k(n,c))||r.enumerable});return e};var B=e=>O(q({},"__esModule",{value:!0}),e);var j={};R(j,{createApi:()=>D});module.exports=B(j);var x=require("react");var g=require("react");function A(e,n=[]){let i,r=[],c=l=>{let s=typeof l=="function"?l(i):l;i={...i,...s},r.forEach(u=>u())},m=()=>i,F=v(c,m,n);i=e(F,m);let w=l=>(r.push(l),()=>{r=r.filter(s=>s!==l)});return()=>(0,g.useSyncExternalStore)(w,m)}var v=(e,n,i)=>!i||i.length===0?e:i.reduceRight((r,c)=>c(e,n)(r),e);function J(e){return e.charAt(0).toUpperCase()+e.slice(1)}var N=async(e,n,i,r,c,m,F)=>{var w,l,s,u,h,p,T;n({isLoading:!0});try{let t=null,o=null,a=i().cashExp,M=Date.now(),S=!1;if(F||JSON.stringify(i().arg||{})!==JSON.stringify(e||{})?S=!1:S=a>=M,S&&(t=i().data),!S&&(r!=null&&r.queryFnc)){n({isFetching:!0});let{data:y,error:E}=await((w=r==null?void 0:r.queryFnc)==null?void 0:w.call(r,e,c));y&&(t=y),E&&(o=E)}else{let y=r.queryFn(e);if(r!=null&&r.transformHeader&&(y.headers=await((l=r==null?void 0:r.transformHeader)==null?void 0:l.call(r,y==null?void 0:y.headers))),r!=null&&r.transformBody&&(y.body=await((s=r==null?void 0:r.transformBody)==null?void 0:s.call(r,y==null?void 0:y.body))),!S){n({isFetching:!0});let{data:E,error:b}=await c(y);E&&(t=E),b&&(o=b)}}return t&&(r!=null&&r.transformResponse&&(t=await((u=r.transformResponse)==null?void 0:u.call(r,t,i().data))),r!=null&&r.onSuccess&&await((h=r.onSuccess)==null?void 0:h.call(r,t))),o&&(r!=null&&r.transformError&&(o=await((p=r.transformError)==null?void 0:p.call(r,o,i().error))),r!=null&&r.onError&&await((T=r.onError)==null?void 0:T.call(r,o))),t?(n({data:t,isSuccess:!0,isLoading:!1,isFetching:!1,cashExp:S?a:Date.now()+m,arg:e}),{data:t}):(n({isLoading:!1,isSuccess:!1,isFetching:!1,isError:!0,error:o,arg:e}),{error:o})}catch(t){return n({isLoading:!1,isSuccess:!1,isFetching:!1,isError:!0,error:t,arg:e}),{error:t}}};async function P(e,n,i,r,c,m,F,w,l){var T,t,o;let s={arg:e,def:r,get:i,set:n};for(let a of l)await((T=a.beforeQuery)==null?void 0:T.call(a,s));let u=-1,h=async a=>{if(a<=u)throw new Error("next() called multiple times");u=a;let M=w[a];return M?M(s,()=>h(a+1)):N(e,n,i,r,c,m,F)},p=await h(0);for(let a of l)await((t=a.afterQuery)==null?void 0:t.call(a,p,s));if(p!=null&&p.error)for(let a of l)await((o=a.onError)==null?void 0:o.call(a,p.error,s));return p}function D(e){let{baseQuery:n,endpoints:i,cacheTimeout:r=30*1e3,middlewares:c=[],plugins:m=[]}=e,w=i({query:s=>({type:"query",queryFn:s.query,...s}),mutation:s=>({type:"mutation",queryFn:s.query,...s})}),l={};for(let s in w){let u=w[s],h=`use${J(s)}`+(u.type==="query"?"Query":"Mutation"),p=(u.plugins||[]).filter(t=>(t==null?void 0:t.middleware)&&typeof t.middleware=="function").map(t=>t.middleware),T=A((t,o)=>({data:null,isLoading:!1,isError:!1,isFetching:!1,isSuccess:!1,error:null,arg:null,cashExp:0,query:a=>P(a,t,o,u,n,r,!1,[...c,...u.middlewares||[],...p],[...m,...u.plugins||[]]),reFetch:()=>{var a;return P((a=o())==null?void 0:a.arg,t,o,u,n,r,!0,[...c,...u.middlewares||[],...p],[...m,...u.plugins||[]])}}));u.type==="query"&&(l[h]=(t,o)=>{let{skip:a}=o||{},{query:M,error:S,isError:y,isLoading:E,isSuccess:b,reFetch:Q,data:L}=T();return(0,x.useEffect)(()=>{a||M(t)},[JSON.stringify(t||{})]),{error:S,isError:y,isLoading:E,isSuccess:b,data:L,reFetch:Q}}),u.type==="mutation"&&(l[h]=()=>{let{query:t,...o}=T();return[t,o]})}return l}0&&(module.exports={createApi});
@@ -0,0 +1 @@
1
+ import{a as Q}from"../chunk-SISWF3T4.mjs";import{useEffect as k}from"react";function x(s){return s.charAt(0).toUpperCase()+s.slice(1)}var H=async(s,u,y,r,h,q,A)=>{var E,l,t,o,m,c,w;u({isLoading:!0});try{let n=null,a=null,i=y().cashExp,S=Date.now(),p=!1;if(A||JSON.stringify(y().arg||{})!==JSON.stringify(s||{})?p=!1:p=i>=S,p&&(n=y().data),!p&&(r!=null&&r.queryFnc)){u({isFetching:!0});let{data:e,error:F}=await((E=r==null?void 0:r.queryFnc)==null?void 0:E.call(r,s,h));e&&(n=e),F&&(a=F)}else{let e=r.queryFn(s);if(r!=null&&r.transformHeader&&(e.headers=await((l=r==null?void 0:r.transformHeader)==null?void 0:l.call(r,e==null?void 0:e.headers))),r!=null&&r.transformBody&&(e.body=await((t=r==null?void 0:r.transformBody)==null?void 0:t.call(r,e==null?void 0:e.body))),!p){u({isFetching:!0});let{data:F,error:b}=await h(e);F&&(n=F),b&&(a=b)}}return n&&(r!=null&&r.transformResponse&&(n=await((o=r.transformResponse)==null?void 0:o.call(r,n,y().data))),r!=null&&r.onSuccess&&await((m=r.onSuccess)==null?void 0:m.call(r,n))),a&&(r!=null&&r.transformError&&(a=await((c=r.transformError)==null?void 0:c.call(r,a,y().error))),r!=null&&r.onError&&await((w=r.onError)==null?void 0:w.call(r,a))),n?(u({data:n,isSuccess:!0,isLoading:!1,isFetching:!1,cashExp:p?i:Date.now()+q,arg:s}),{data:n}):(u({isLoading:!1,isSuccess:!1,isFetching:!1,isError:!0,error:a,arg:s}),{error:a})}catch(n){return u({isLoading:!1,isSuccess:!1,isFetching:!1,isError:!0,error:n,arg:s}),{error:n}}};async function M(s,u,y,r,h,q,A,E,l){var w,n,a;let t={arg:s,def:r,get:y,set:u};for(let i of l)await((w=i.beforeQuery)==null?void 0:w.call(i,t));let o=-1,m=async i=>{if(i<=o)throw new Error("next() called multiple times");o=i;let S=E[i];return S?S(t,()=>m(i+1)):H(s,u,y,r,h,q,A)},c=await m(0);for(let i of l)await((n=i.afterQuery)==null?void 0:n.call(i,c,t));if(c!=null&&c.error)for(let i of l)await((a=i.onError)==null?void 0:a.call(i,c.error,t));return c}function O(s){let{baseQuery:u,endpoints:y,cacheTimeout:r=30*1e3,middlewares:h=[],plugins:q=[]}=s,E=y({query:t=>({type:"query",queryFn:t.query,...t}),mutation:t=>({type:"mutation",queryFn:t.query,...t})}),l={};for(let t in E){let o=E[t],m=`use${x(t)}`+(o.type==="query"?"Query":"Mutation"),c=(o.plugins||[]).filter(n=>(n==null?void 0:n.middleware)&&typeof n.middleware=="function").map(n=>n.middleware),w=Q((n,a)=>({data:null,isLoading:!1,isError:!1,isFetching:!1,isSuccess:!1,error:null,arg:null,cashExp:0,query:i=>M(i,n,a,o,u,r,!1,[...h,...o.middlewares||[],...c],[...q,...o.plugins||[]]),reFetch:()=>{var i;return M((i=a())==null?void 0:i.arg,n,a,o,u,r,!0,[...h,...o.middlewares||[],...c],[...q,...o.plugins||[]])}}));o.type==="query"&&(l[m]=(n,a)=>{let{skip:i}=a||{},{query:S,error:p,isError:e,isLoading:F,isSuccess:b,reFetch:T,data:g}=w();return k(()=>{i||S(n)},[JSON.stringify(n||{})]),{error:p,isError:e,isLoading:F,isSuccess:b,data:g,reFetch:T}}),o.type==="mutation"&&(l[m]=()=>{let{query:n,...a}=w();return[n,a]})}return l}export{O as createApi};
package/package.json CHANGED
@@ -1,21 +1,21 @@
1
1
  {
2
2
  "name": "zustic",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "A fast, minimal state management solution for React ecosystems. Works seamlessly with React, Next.js, and React Native, offering predictable state updates with a tiny footprint.",
5
- "main": "dist/index.js",
6
- "module": "dist/index.mjs",
7
- "types": "dist/index.d.ts",
8
5
  "scripts": {
9
- "build": "tsup src/index.ts --format esm,cjs --dts --clean --external react",
10
- "start:cjs": "node dist/cjs/index.js",
11
- "start:esm": "node dist/esm/index.js",
12
- "start": "ts-node src/index.ts",
6
+ "build": "tsup",
13
7
  "test": "npm run build && npm link"
14
8
  },
15
9
  "exports": {
16
10
  ".": {
17
- "require": "./dist/index.js",
18
- "import": "./dist/index.mjs"
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.mjs",
13
+ "require": "./dist/index.js"
14
+ },
15
+ "./query": {
16
+ "types": "./dist/query/index.d.ts",
17
+ "import": "./dist/query/index.mjs",
18
+ "require": "./dist/query/index.js"
19
19
  }
20
20
  },
21
21
  "directories": {
@@ -38,7 +38,7 @@
38
38
  "nextjs",
39
39
  "state"
40
40
  ],
41
- "homepage": "https://zustic.github.io/",
41
+ "homepage": "https://zustic.github.io",
42
42
  "files": [
43
43
  "dist/**/*",
44
44
  "README.md"