native-document 1.0.92 → 1.0.93

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 (68) hide show
  1. package/dist/native-document.components.min.js +1088 -65
  2. package/dist/native-document.dev.js +695 -142
  3. package/dist/native-document.dev.js.map +1 -1
  4. package/dist/native-document.devtools.min.js +1 -1
  5. package/dist/native-document.min.js +1 -1
  6. package/docs/advanced-components.md +814 -0
  7. package/docs/anchor.md +71 -11
  8. package/docs/cache.md +888 -0
  9. package/docs/conditional-rendering.md +91 -1
  10. package/docs/core-concepts.md +9 -2
  11. package/docs/elements.md +127 -2
  12. package/docs/extending-native-document-element.md +7 -1
  13. package/docs/filters.md +1216 -0
  14. package/docs/getting-started.md +12 -3
  15. package/docs/lifecycle-events.md +10 -2
  16. package/docs/list-rendering.md +453 -54
  17. package/docs/memory-management.md +9 -7
  18. package/docs/native-document-element.md +30 -9
  19. package/docs/native-fetch.md +744 -0
  20. package/docs/observables.md +135 -6
  21. package/docs/routing.md +7 -1
  22. package/docs/state-management.md +7 -1
  23. package/docs/validation.md +8 -1
  24. package/eslint.config.js +3 -3
  25. package/package.json +3 -2
  26. package/readme.md +53 -14
  27. package/src/components/$traits/HasItems.js +42 -1
  28. package/src/components/BaseComponent.js +4 -1
  29. package/src/components/accordion/Accordion.js +112 -8
  30. package/src/components/accordion/AccordionItem.js +93 -4
  31. package/src/components/alert/Alert.js +164 -4
  32. package/src/components/avatar/Avatar.js +236 -22
  33. package/src/components/menu/index.js +1 -2
  34. package/src/core/data/ObservableArray.js +120 -2
  35. package/src/core/data/ObservableChecker.js +50 -0
  36. package/src/core/data/ObservableItem.js +124 -4
  37. package/src/core/data/ObservableWhen.js +36 -6
  38. package/src/core/data/observable-helpers/array.js +12 -3
  39. package/src/core/data/observable-helpers/computed.js +17 -4
  40. package/src/core/data/observable-helpers/object.js +19 -3
  41. package/src/core/elements/control/for-each-array.js +20 -2
  42. package/src/core/elements/control/for-each.js +17 -5
  43. package/src/core/elements/control/show-if.js +31 -15
  44. package/src/core/elements/control/show-when.js +23 -0
  45. package/src/core/elements/control/switch.js +40 -10
  46. package/src/core/utils/cache.js +5 -0
  47. package/src/core/utils/memoize.js +25 -16
  48. package/src/core/utils/prototypes.js +3 -2
  49. package/src/core/wrappers/AttributesWrapper.js +1 -1
  50. package/src/core/wrappers/NDElement.js +41 -1
  51. package/src/core/wrappers/NdPrototype.js +4 -0
  52. package/src/core/wrappers/TemplateCloner.js +13 -10
  53. package/src/core/wrappers/prototypes/bind-class-extensions.js +1 -1
  54. package/src/core/wrappers/prototypes/nd-element-extensions.js +3 -0
  55. package/src/router/Route.js +9 -4
  56. package/src/router/Router.js +28 -9
  57. package/src/router/errors/RouterError.js +0 -1
  58. package/types/control-flow.d.ts +9 -6
  59. package/types/elements.d.ts +6 -3
  60. package/types/filters/index.d.ts +4 -0
  61. package/types/nd-element.d.ts +5 -238
  62. package/types/observable.d.ts +9 -3
  63. package/types/router.d.ts +5 -1
  64. package/types/template-cloner.ts +1 -0
  65. package/types/validator.ts +11 -1
  66. package/utils.d.ts +2 -1
  67. package/utils.js +4 -4
  68. package/src/core/utils/service.js +0 -6
@@ -0,0 +1,744 @@
1
+ # NativeFetch
2
+
3
+ NativeFetch is a powerful HTTP client built on top of the native Fetch API, providing a clean interface with interceptors, automatic request/response handling, and advanced features for modern web applications.
4
+
5
+ ## Overview
6
+
7
+ NativeFetch enhances the standard Fetch API with:
8
+ - **Interceptors** - Request and response transformation
9
+ - **Base URL** - Centralized endpoint configuration
10
+ - **Automatic JSON handling** - Parse and stringify automatically
11
+ - **Error handling** - Consistent error responses
12
+ - **Request cancellation** - AbortController integration
13
+ - **TypeScript-friendly** - Clean, predictable API
14
+
15
+ ## Import
16
+ ```javascript
17
+ import { NativeFetch } from 'native-document/utils';
18
+ ```
19
+
20
+ ## Basic Usage
21
+
22
+ ### Creating an Instance
23
+ ```javascript
24
+ import { NativeFetch } from 'native-document/utils';
25
+
26
+ // Create client with base URL
27
+ const api = new NativeFetch('https://api.example.com');
28
+
29
+ // Make requests
30
+ const users = await api.get('/users');
31
+ const user = await api.get('/users/123');
32
+ const newUser = await api.post('/users', { name: 'Alice', email: 'alice@example.com' });
33
+ ```
34
+
35
+ ### HTTP Methods
36
+ ```javascript
37
+ import { NativeFetch } from 'native-document/utils';
38
+
39
+ const api = new NativeFetch('https://api.example.com');
40
+
41
+ // GET request
42
+ const data = await api.get('/endpoint');
43
+ const dataWithParams = await api.get('/endpoint', { page: 1, limit: 10 });
44
+
45
+ // POST request
46
+ const created = await api.post('/endpoint', {
47
+ name: 'New Item',
48
+ description: 'Description'
49
+ });
50
+
51
+ // PUT request
52
+ const updated = await api.put('/endpoint/123', {
53
+ name: 'Updated Item'
54
+ });
55
+
56
+ // PATCH request
57
+ const patched = await api.patch('/endpoint/123', {
58
+ status: 'active'
59
+ });
60
+
61
+ // DELETE request
62
+ const deleted = await api.delete('/endpoint/123');
63
+ ```
64
+
65
+ ### Query Parameters
66
+ ```javascript
67
+ import { NativeFetch } from 'native-document/utils';
68
+
69
+ const api = new NativeFetch('https://api.example.com');
70
+
71
+ // Pass query parameters as object
72
+ const users = await api.get('/users', {
73
+ page: 1,
74
+ limit: 20,
75
+ sort: 'name',
76
+ filter: 'active'
77
+ });
78
+ // Request: GET /users?page=1&limit=20&sort=name&filter=active
79
+
80
+ // Array parameters
81
+ const posts = await api.get('/posts', {
82
+ tags: ['javascript', 'tutorial'],
83
+ categories: ['tech', 'programming']
84
+ });
85
+ // Request: GET /posts?tags=javascript,tutorial&categories=tech,programming
86
+ ```
87
+
88
+ ## Interceptors
89
+
90
+ Interceptors allow you to transform requests before they're sent and responses before they're returned.
91
+
92
+ ### Request Interceptors
93
+ ```javascript
94
+ import { NativeFetch } from 'native-document/utils';
95
+
96
+ const api = new NativeFetch('https://api.example.com');
97
+
98
+ // Add authentication header
99
+ api.interceptors.request((config) => {
100
+ const token = localStorage.getItem('auth_token');
101
+ if (token) {
102
+ config.headers['Authorization'] = `Bearer ${token}`;
103
+ }
104
+ return config;
105
+ });
106
+
107
+ // Add custom headers
108
+ api.interceptors.request((config) => {
109
+ config.headers['X-App-Version'] = '1.0.0';
110
+ config.headers['X-Request-ID'] = generateRequestId();
111
+ return config;
112
+ });
113
+
114
+ // Log requests
115
+ api.interceptors.request((config) => {
116
+ console.log(`[${config.method}] ${config.url}`);
117
+ return config;
118
+ });
119
+ ```
120
+
121
+ ### Response Interceptors
122
+ ```javascript
123
+ import { NativeFetch } from 'native-document/utils';
124
+
125
+ const api = new NativeFetch('https://api.example.com');
126
+
127
+ // Handle authentication errors
128
+ api.interceptors.response((response) => {
129
+ if (response.status === 401) {
130
+ // Redirect to login
131
+ window.location.href = '/login';
132
+ throw new Error('Unauthorized');
133
+ }
134
+ return response;
135
+ });
136
+
137
+ // Transform response data
138
+ api.interceptors.response((response) => {
139
+ // Unwrap data from envelope
140
+ if (response.data && response.data.result) {
141
+ return {
142
+ ...response,
143
+ data: response.data.result
144
+ };
145
+ }
146
+ return response;
147
+ });
148
+
149
+ // Log responses
150
+ api.interceptors.response((response) => {
151
+ console.log(`[${response.status}] ${response.url}`);
152
+ return response;
153
+ });
154
+
155
+ // Handle errors globally
156
+ api.interceptors.response((response) => {
157
+ if (!response.ok) {
158
+ console.error(`Error: ${response.status} - ${response.statusText}`);
159
+ }
160
+ return response;
161
+ });
162
+ ```
163
+
164
+ ### Multiple Interceptors
165
+ ```javascript
166
+ import { NativeFetch } from 'native-document/utils';
167
+
168
+ const api = new NativeFetch('https://api.example.com');
169
+
170
+ // Interceptors are executed in order
171
+ api.interceptors.request((config) => {
172
+ console.log('Interceptor 1');
173
+ return config;
174
+ });
175
+
176
+ api.interceptors.request((config) => {
177
+ console.log('Interceptor 2');
178
+ return config;
179
+ });
180
+
181
+ // When making a request:
182
+ await api.get('/users');
183
+ // Logs: "Interceptor 1"
184
+ // Logs: "Interceptor 2"
185
+ ```
186
+
187
+ ## Advanced Features
188
+
189
+ ### Custom Headers
190
+ ```javascript
191
+ import { NativeFetch } from 'native-document/utils';
192
+
193
+ const api = new NativeFetch('https://api.example.com');
194
+
195
+ // Set default headers
196
+ api.interceptors.request((config) => {
197
+ config.headers['Content-Type'] = 'application/json';
198
+ config.headers['Accept'] = 'application/json';
199
+ return config;
200
+ });
201
+
202
+ // Per-request headers
203
+ const data = await api.get('/endpoint', {}, {
204
+ headers: {
205
+ 'X-Custom-Header': 'value'
206
+ }
207
+ });
208
+ ```
209
+
210
+ ### Retry Logic
211
+ ```javascript
212
+ import { NativeFetch } from 'native-document/utils';
213
+
214
+ const api = new NativeFetch('https://api.example.com');
215
+
216
+ // Add retry logic
217
+ api.interceptors.response(async (response) => {
218
+ if (response.status === 429) {
219
+ // Rate limited - wait and retry
220
+ const retryAfter = response.headers.get('Retry-After') || 1;
221
+ await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
222
+
223
+ // Retry the request
224
+ return fetch(response.url, response.config);
225
+ }
226
+ return response;
227
+ });
228
+ ```
229
+
230
+ ## Practical Examples
231
+
232
+ ### Authentication Flow
233
+ ```javascript
234
+ import { NativeFetch } from 'native-document/utils';
235
+ import { Store } from 'native-document';
236
+
237
+ const api = new NativeFetch('https://api.example.com');
238
+
239
+ // Create auth store
240
+ Store.create('auth', {
241
+ user: null,
242
+ token: null,
243
+ isAuthenticated: false
244
+ });
245
+
246
+ // Add token to requests
247
+ api.interceptors.request((config) => {
248
+ const auth = Store.get('auth').val();
249
+ if (auth.token) {
250
+ config.headers['Authorization'] = `Bearer ${auth.token}`;
251
+ }
252
+ return config;
253
+ });
254
+
255
+ // Handle unauthorized
256
+ api.interceptors.response((response) => {
257
+ if (response.status === 401) {
258
+ const auth = Store.get('auth');
259
+ auth.set({
260
+ user: null,
261
+ token: null,
262
+ isAuthenticated: false
263
+ });
264
+ window.location.href = '/login';
265
+ }
266
+ return response;
267
+ });
268
+
269
+ // Login function
270
+ async function login(email, password) {
271
+ const { data } = await api.post('/auth/login', { email, password });
272
+
273
+ const auth = Store.get('auth');
274
+ auth.set({
275
+ user: data.user,
276
+ token: data.token,
277
+ isAuthenticated: true
278
+ });
279
+
280
+ return data;
281
+ }
282
+
283
+ // Logout function
284
+ async function logout() {
285
+ await api.post('/auth/logout');
286
+
287
+ const auth = Store.get('auth');
288
+ auth.set({
289
+ user: null,
290
+ token: null,
291
+ isAuthenticated: false
292
+ });
293
+ }
294
+ ```
295
+
296
+ ### API Service Layer
297
+ ```javascript
298
+ import { NativeFetch } from 'native-document/utils';
299
+ import { Cache } from 'native-document/utils';
300
+
301
+ // Create API client singleton
302
+ const getAPI = Cache.singleton(() => {
303
+ const client = new NativeFetch('https://api.example.com');
304
+
305
+ // Add interceptors
306
+ client.interceptors.request((config) => {
307
+ config.headers['Content-Type'] = 'application/json';
308
+ const token = localStorage.getItem('token');
309
+ if (token) {
310
+ config.headers['Authorization'] = `Bearer ${token}`;
311
+ }
312
+ return config;
313
+ });
314
+
315
+ return client;
316
+ });
317
+
318
+ // API endpoints by resource
319
+ export const API = Cache.memoize((resource) => {
320
+ const client = getAPI();
321
+
322
+ return {
323
+ list: (params = {}) => client.get(`/${resource}`, params),
324
+ get: (id) => client.get(`/${resource}/${id}`),
325
+ create: (data) => client.post(`/${resource}`, data),
326
+ update: (id, data) => client.put(`/${resource}/${id}`, data),
327
+ patch: (id, data) => client.patch(`/${resource}/${id}`, data),
328
+ delete: (id) => client.delete(`/${resource}/${id}`)
329
+ };
330
+ });
331
+
332
+ // Usage
333
+ const users = await API.users.list({ page: 1, limit: 10 });
334
+ const user = await API.users.get('123');
335
+ const newUser = await API.users.create({ name: 'Alice' });
336
+ await API.users.update('123', { name: 'Alice Updated' });
337
+ await API.users.delete('123');
338
+ ```
339
+
340
+ ### Loading States
341
+ ```javascript
342
+ import { NativeFetch } from 'native-document/utils';
343
+ import { Observable } from 'native-document';
344
+
345
+ const api = new NativeFetch('https://api.example.com');
346
+
347
+ const isLoading = Observable(false);
348
+ const loadingCount = Observable(0);
349
+
350
+ // Track loading state
351
+ api.interceptors.request((config) => {
352
+ loadingCount.set(loadingCount.val() + 1);
353
+ isLoading.set(true);
354
+ return config;
355
+ });
356
+
357
+ api.interceptors.response((response) => {
358
+ const count = loadingCount.val() - 1;
359
+ loadingCount.set(count);
360
+ if (count === 0) {
361
+ isLoading.set(false);
362
+ }
363
+ return response;
364
+ });
365
+
366
+ // Use in UI
367
+ import { Div } from 'native-document/src/elements';
368
+ import { ShowIf } from 'native-document';
369
+
370
+ const LoadingIndicator = Div({ class: 'loading-indicator' }, [
371
+ ShowIf(isLoading, () =>
372
+ Div({ class: 'spinner' }, 'Loading...')
373
+ )
374
+ ]);
375
+ ```
376
+
377
+ ### Error Handling
378
+ ```javascript
379
+ import { NativeFetch } from 'native-document/utils';
380
+ import { Observable } from 'native-document';
381
+
382
+ const api = new NativeFetch('https://api.example.com');
383
+ const globalError = Observable(null);
384
+
385
+ // Global error handler
386
+ api.interceptors.response((response) => {
387
+ if (!response.ok) {
388
+ const error = {
389
+ status: response.status,
390
+ message: response.statusText,
391
+ url: response.url
392
+ };
393
+
394
+ globalError.set(error);
395
+
396
+ // Auto-clear after 5 seconds
397
+ setTimeout(() => globalError.set(null), 5000);
398
+ }
399
+ return response;
400
+ });
401
+
402
+ // Error display component
403
+ import { Div } from 'native-document/src/elements';
404
+ import { ShowIf } from 'native-document';
405
+
406
+ const ErrorNotification = Div([
407
+ ShowIf(globalError, () =>
408
+ Div({
409
+ class: 'error-notification',
410
+ style: {
411
+ position: 'fixed',
412
+ top: '20px',
413
+ right: '20px',
414
+ background: '#ff4444',
415
+ color: 'white',
416
+ padding: '16px',
417
+ borderRadius: '8px'
418
+ }
419
+ }, [
420
+ globalError.check(err => err ? err.message : '')
421
+ ])
422
+ )
423
+ ]);
424
+ ```
425
+
426
+ ### Request Logging
427
+ ```javascript
428
+ import { NativeFetch } from 'native-document/utils';
429
+
430
+ const api = new NativeFetch('https://api.example.com');
431
+
432
+ // Log all requests
433
+ api.interceptors.request((config) => {
434
+ console.group(`🔵 ${config.method} ${config.url}`);
435
+ console.log('Headers:', config.headers);
436
+ console.log('Body:', config.body);
437
+ console.log('Timestamp:', new Date().toISOString());
438
+ console.groupEnd();
439
+ return config;
440
+ });
441
+
442
+ // Log all responses
443
+ api.interceptors.response((response) => {
444
+ const color = response.ok ? '🟢' : '🔴';
445
+ console.group(`${color} ${response.status} ${response.url}`);
446
+ console.log('Status:', response.statusText);
447
+ console.log('Data:', response.data);
448
+ console.log('Duration:', /* calculate duration */);
449
+ console.groupEnd();
450
+ return response;
451
+ });
452
+ ```
453
+
454
+ ### Analytics Tracking
455
+ ```javascript
456
+ import { NativeFetch } from 'native-document/utils';
457
+
458
+ const api = new NativeFetch('https://api.example.com');
459
+
460
+ // Track API calls
461
+ api.interceptors.request((config) => {
462
+ config._startTime = Date.now();
463
+ return config;
464
+ });
465
+
466
+ api.interceptors.response((response) => {
467
+ const duration = Date.now() - response.config._startTime;
468
+
469
+ // Send to analytics
470
+ if (window.analytics) {
471
+ window.analytics.track('api_request', {
472
+ method: response.config.method,
473
+ endpoint: response.url,
474
+ status: response.status,
475
+ duration: duration,
476
+ success: response.ok
477
+ });
478
+ }
479
+
480
+ return response;
481
+ });
482
+ ```
483
+
484
+ ## Response Format
485
+
486
+ NativeFetch automatically parses JSON responses and provides a consistent response object:
487
+ ```javascript
488
+ {
489
+ ok: boolean, // true if status 200-299
490
+ status: number, // HTTP status code
491
+ statusText: string, // Status message
492
+ headers: Headers, // Response headers
493
+ data: any, // Parsed JSON data
494
+ url: string, // Request URL
495
+ config: object // Original request config
496
+ }
497
+ ```
498
+
499
+ ### Handling Different Response Types
500
+ ```javascript
501
+ import { NativeFetch } from 'native-document/utils';
502
+
503
+ const api = new NativeFetch('https://api.example.com');
504
+
505
+ // JSON response (default)
506
+ const json = await api.get('/data');
507
+ console.log(json.data);
508
+
509
+ // Text response
510
+ const response = await fetch('https://api.example.com/text');
511
+ const text = await response.text();
512
+
513
+ // Blob response (files, images)
514
+ const blobResponse = await fetch('https://api.example.com/image.png');
515
+ const blob = await blobResponse.blob();
516
+ const imageUrl = URL.createObjectURL(blob);
517
+ ```
518
+
519
+ ## Error Handling
520
+
521
+ ### Try-Catch Pattern
522
+ ```javascript
523
+ import { NativeFetch } from 'native-document/utils';
524
+
525
+ const api = new NativeFetch('https://api.example.com');
526
+
527
+ try {
528
+ const data = await api.get('/endpoint');
529
+ console.log('Success:', data);
530
+ } catch (error) {
531
+ if (error.response) {
532
+ // Server responded with error
533
+ console.error('Server error:', error.response.status);
534
+ console.error('Message:', error.response.data);
535
+ } else if (error.request) {
536
+ // Request made but no response
537
+ console.error('Network error:', error.message);
538
+ } else {
539
+ // Other errors
540
+ console.error('Error:', error.message);
541
+ }
542
+ }
543
+ ```
544
+
545
+ ### Async Error Boundaries
546
+ ```javascript
547
+ import { NativeFetch } from 'native-document/utils';
548
+ import { Observable } from 'native-document';
549
+
550
+ const api = new NativeFetch('https://api.example.com');
551
+
552
+ async function fetchData() {
553
+ const data = Observable(null);
554
+ const error = Observable(null);
555
+ const loading = Observable(true);
556
+
557
+ try {
558
+ const response = await api.get('/data');
559
+ data.set(response.data);
560
+ } catch (err) {
561
+ error.set(err.message);
562
+ } finally {
563
+ loading.set(false);
564
+ }
565
+
566
+ return { data, error, loading };
567
+ }
568
+ ```
569
+
570
+ ## Best Practices
571
+
572
+ ### 1. Create Singleton API Client
573
+ ```javascript
574
+ import { Cache } from 'native-document/utils';
575
+ import { NativeFetch } from 'native-document/utils';
576
+
577
+ // ✅ Good: Single instance with interceptors
578
+ const getAPI = Cache.singleton(() => {
579
+ const client = new NativeFetch('https://api.example.com');
580
+
581
+ client.interceptors.request((config) => {
582
+ // Add auth header
583
+ return config;
584
+ });
585
+
586
+ return client;
587
+ });
588
+
589
+ // ❌ Bad: New instance every time
590
+ function makeRequest() {
591
+ const api = new NativeFetch('https://api.example.com');
592
+ return api.get('/data');
593
+ }
594
+ ```
595
+
596
+ ### 2. Use Resource-Based Endpoints
597
+ ```javascript
598
+ import { Cache } from 'native-document/utils';
599
+
600
+ // ✅ Good: Organized by resource
601
+ const API = Cache.memoize((resource) => ({
602
+ list: () => api.get(`/${resource}`),
603
+ get: (id) => api.get(`/${resource}/${id}`),
604
+ create: (data) => api.post(`/${resource}`, data)
605
+ }));
606
+
607
+ // ❌ Bad: Scattered API calls
608
+ async function getUsers() {
609
+ return api.get('/users');
610
+ }
611
+ async function getUser(id) {
612
+ return api.get('/users/' + id);
613
+ }
614
+ ```
615
+
616
+ ### 3. Handle Errors Consistently
617
+ ```javascript
618
+ import { NativeFetch } from 'native-document/utils';
619
+
620
+ const api = new NativeFetch('https://api.example.com');
621
+
622
+ // ✅ Good: Centralized error handling
623
+ api.interceptors.response((response) => {
624
+ if (!response.ok) {
625
+ handleError(response);
626
+ }
627
+ return response;
628
+ });
629
+
630
+ // ❌ Bad: Error handling in every request
631
+ try {
632
+ await api.get('/endpoint1');
633
+ } catch (error) {
634
+ showError(error);
635
+ }
636
+
637
+ try {
638
+ await api.get('/endpoint2');
639
+ } catch (error) {
640
+ showError(error);
641
+ }
642
+ ```
643
+
644
+ ### 4. Use Query Parameters Object
645
+ ```javascript
646
+ import { NativeFetch } from 'native-document/utils';
647
+
648
+ const api = new NativeFetch('https://api.example.com');
649
+
650
+ // ✅ Good: Clean object syntax
651
+ const users = await api.get('/users', {
652
+ page: 1,
653
+ limit: 20,
654
+ sort: 'name'
655
+ });
656
+
657
+ // ❌ Bad: Manual query string
658
+ const users = await api.get('/users?page=1&limit=20&sort=name');
659
+ ```
660
+
661
+ ### 5. Type Your Responses
662
+ ```javascript
663
+ import { NativeFetch } from 'native-document/utils';
664
+
665
+ const api = new NativeFetch('https://api.example.com');
666
+
667
+ // ✅ Good: Document expected response
668
+ /**
669
+ * @returns {Promise<{data: User[]}>}
670
+ */
671
+ async function getUsers() {
672
+ return await api.get('/users');
673
+ }
674
+
675
+ // Use with confidence
676
+ const { data } = await getUsers();
677
+ data.forEach(user => console.log(user.name));
678
+ ```
679
+
680
+ ## Performance Tips
681
+
682
+ ### 1. Reuse Client Instances
683
+ ```javascript
684
+ import { Cache } from 'native-document/utils';
685
+
686
+ // ✅ Singleton - created once
687
+ const getAPI = Cache.singleton(() => new NativeFetch('https://api.example.com'));
688
+ ```
689
+
690
+ ### 2. Cancel Unnecessary Requests
691
+ ```javascript
692
+ let controller = new AbortController();
693
+
694
+ async function search(query) {
695
+ // Cancel previous request
696
+ controller.abort();
697
+ controller = new AbortController();
698
+
699
+ return await api.get('/search', { q: query }, {
700
+ signal: controller.signal
701
+ });
702
+ }
703
+ ```
704
+
705
+ ### 3. Batch Related Requests
706
+ ```javascript
707
+ // ✅ Good: Batch requests
708
+ const [users, posts, comments] = await Promise.all([
709
+ api.get('/users'),
710
+ api.get('/posts'),
711
+ api.get('/comments')
712
+ ]);
713
+
714
+ // ❌ Bad: Sequential requests
715
+ const users = await api.get('/users');
716
+ const posts = await api.get('/posts');
717
+ const comments = await api.get('/comments');
718
+ ```
719
+
720
+ ## Next Steps
721
+
722
+ Explore related utilities and concepts:
723
+
724
+ ## Next Steps
725
+
726
+ - **[Getting Started](getting-started.md)** - Installation and first steps
727
+ - **[Core Concepts](core-concepts.md)** - Understanding the fundamentals
728
+ - **[Observables](observables.md)** - Reactive state management
729
+ - **[Elements](elements.md)** - Creating and composing UI
730
+ - **[Conditional Rendering](conditional-rendering.md)** - Dynamic content
731
+ - **[List Rendering](list-rendering.md)** - (ForEach | ForEachArray) and dynamic lists
732
+ - **[Routing](routing.md)** - Navigation and URL management
733
+ - **[State Management](state-management.md)** - Global state patterns
734
+ - **[NDElement](native-document-element.md)** - Native Document Element
735
+ - **[Extending NDElement](extending-native-document-element.md)** - Custom Methods Guide
736
+ - **[Advanced Components](advanced-components.md)** - Template caching and singleton views
737
+ - **[Args Validation](validation.md)** - Function Argument Validation
738
+ - **[Memory Management](memory-management.md)** - Memory management
739
+
740
+ ## Utilities
741
+
742
+ - **[Cache](docs/utils/cache.md)** - Lazy initialization and singleton patterns
743
+ - **[NativeFetch](docs/utils/native-fetch.md)** - HTTP client with interceptors
744
+ - **[Filters](docs/utils/filters.md)** - Data filtering helpers