bytekit 0.2.7 → 1.0.0

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
@@ -7,44 +7,17 @@
7
7
 
8
8
  ---
9
9
 
10
- ## Overview / Resumen
10
+ ## Highlights / Características
11
11
 
12
- **EN:** Ship consistent networking, logging, and helper APIs across Node.js and browsers with zero setup—everything is published as ESM plus typings.
13
- **ES:** Centralizá networking, logging y helpers tanto en Node.js como en navegadores sin configuración extra: todo se publica en ESM con definiciones de tipos.
12
+ - ✅ **EN:** Fully ESM with `.d.ts` definitions. **ES:** Build 100% ESM con tipos listos.
13
+ - 🌐 **EN:** Works on Node.js 18+ and modern browsers (via `cross-fetch`). **ES:** Compatible con Node.js 18+ y navegadores modernos (usa `cross-fetch`).
14
+ - 🔁 **EN:** ApiClient with retries, localized errors, flexible options. **ES:** ApiClient con reintentos, errores localizados y configuración flexible.
15
+ - 🧩 **EN:** Helper modules (strings, dates, validators, env, storage). **ES:** Helpers para strings, fechas, validadores, env y storage.
16
+ - 🪵 **EN:** Structured logging/profiling: `createLogger`, `Profiler`, `withTiming`. **ES:** Logging/profiling estructurado: `createLogger`, `Profiler`, `withTiming`.
14
17
 
15
- ## Highlights / Características
18
+ ## 🚀 Quick Start / Inicio Rápido
16
19
 
17
- - ✅ **EN:** Fully ESM with `.d.ts` definitions. **ES:** Build 100 % ESM con tipos listos.
18
- - 🌐 **EN:** Works on Node.js 18+ and modern browsers (via `cross-fetch`). **ES:** Compatible con Node.js 18+ y navegadores modernos (usa `cross-fetch`).
19
- - 🔁 **EN:** ApiClient with retries, localized errors, flexible options. **ES:** ApiClient con reintentos, errores localizados y configuración flexible.
20
- - 🧩 **EN:** Helper modules (strings, dates, validators, env, storage). **ES:** Helpers para strings, fechas, validadores, env y storage.
21
- - 🪵 **EN:** Structured logging/profiling: `createLogger`, `Profiler`, `withTiming`. **ES:** Logging/profiling estructurado: `createLogger`, `Profiler`, `withTiming`.
22
-
23
- ## Installation / Instalación
24
-
25
- ### Global Installation / Instalación Global
26
-
27
- **EN:** Install the package globally to use the CLI tool (`sutils`) from anywhere.
28
- **ES:** Instalá el paquete globalmente para usar la herramienta CLI (`sutils`) desde cualquier lugar.
29
-
30
- ```bash
31
- npm install -g bytekit
32
- # or / o
33
- pnpm add -g bytekit
34
- ```
35
-
36
- **EN:** After global installation, you can use the `sutils` command:
37
- **ES:** Después de la instalación global, podés usar el comando `sutils`:
38
-
39
- ```bash
40
- sutils create users
41
- sutils types https://api.example.com/users
42
- ```
43
-
44
- ### Project Installation / Instalación en Proyecto
45
-
46
- **EN:** Install as a project dependency to use all utilities in your application.
47
- **ES:** Instalá como dependencia del proyecto para usar todos los utilities en tu aplicación.
20
+ ### Installation / Instalación
48
21
 
49
22
  ```bash
50
23
  npm install bytekit
@@ -54,166 +27,16 @@ pnpm add bytekit
54
27
  yarn add bytekit
55
28
  ```
56
29
 
57
- ### Modular Installation / Instalación Modular
58
-
59
- **EN:** Import only the modules you need to reduce bundle size. Each utility can be imported individually.
60
- **ES:** Importá solo los módulos que necesitás para reducir el tamaño del bundle. Cada utility se puede importar individualmente.
61
-
62
- #### Core Modules / Módulos Core
63
-
64
- ```ts
65
- // HTTP Client
66
- import { ApiClient, createApiClient } from "bytekit/api-client";
67
-
68
- // Retry & Circuit Breaker
69
- import { RetryPolicy, CircuitBreaker } from "bytekit/retry-policy";
70
-
71
- // Response Validation
72
- import { ResponseValidator } from "bytekit/response-validator";
73
-
74
- // Logging
75
- import { Logger, createLogger } from "bytekit/logger";
76
-
77
- // Profiling
78
- import { Profiler } from "bytekit/profiler";
79
-
80
- // Debug Utilities
81
- import { createStopwatch, withTiming, measureAsync } from "bytekit/debug";
82
-
83
- // Request Caching
84
- import { RequestCache } from "bytekit/request-cache";
85
-
86
- // Rate Limiting
87
- import { RateLimiter, SlidingWindowRateLimiter } from "bytekit/rate-limiter";
88
-
89
- // Request Deduplication
90
- import { RequestDeduplicator } from "bytekit/request-deduplicator";
91
-
92
- // Error Boundary
93
- import { ErrorBoundary, getGlobalErrorBoundary } from "bytekit/error-boundary";
94
- ```
95
-
96
- #### Helper Modules / Módulos Helpers
97
-
98
- ```ts
99
- // Date Utilities
100
- import { DateUtils } from "bytekit/date-utils";
101
-
102
- // String Utilities
103
- import { StringUtils } from "bytekit/string-utils";
104
-
105
- // Validation
106
- import { Validator } from "bytekit/validator";
107
-
108
- // Environment Manager
109
- import { EnvManager } from "bytekit/env-manager";
110
-
111
- // Storage Utilities
112
- import { StorageUtils } from "bytekit/storage-utils";
113
-
114
- // File Upload
115
- import { FileUploadHelper } from "bytekit/file-upload";
116
-
117
- // Streaming
118
- import { StreamingHelper } from "bytekit/streaming";
119
-
120
- // WebSocket
121
- import { WebSocketHelper } from "bytekit/websocket";
122
-
123
- // Array Utilities
124
- import { ArrayUtils } from "bytekit/array-utils";
125
-
126
- // Object Utilities
127
- import { ObjectUtils } from "bytekit/object-utils";
128
-
129
- // Form Utilities
130
- import { FormUtils, createForm } from "bytekit/form-utils";
131
-
132
- // Time Utilities
133
- import { TimeUtils } from "bytekit/time-utils";
134
-
135
- // Event Emitter
136
- import { EventEmitter, createEventEmitter } from "bytekit/event-emitter";
137
-
138
- // Diff Utilities
139
- import { DiffUtils } from "bytekit/diff-utils";
140
-
141
- // Polling Helper
142
- import { PollingHelper, createPoller } from "bytekit/polling-helper";
143
-
144
- // Crypto Utilities
145
- import { CryptoUtils } from "bytekit/crypto-utils";
146
-
147
- // Pagination Helper
148
- import { PaginationHelper, createPaginator } from "bytekit/pagination-helper";
149
-
150
- // Cache Manager
151
- import { CacheManager, createCacheManager } from "bytekit/cache-manager";
152
-
153
- // Compression Utilities
154
- import { CompressionUtils } from "bytekit/compression-utils";
155
-
156
- // HTTP Status Helper
157
- import { HTTP_STATUS, isSuccess, isRetryable } from "bytekit/http-status";
158
-
159
- // URL Builder
160
- import { UrlBuilder, createUrlBuilder } from "bytekit/url-builder";
161
-
162
- // Batch Request
163
- import { BatchRequest, createBatchRequest } from "bytekit/batch-request";
164
- ```
165
-
166
- #### Import Everything / Importar Todo
167
-
168
- **EN:** You can also import everything from the main entry point:
169
- **ES:** También podés importar todo desde el punto de entrada principal:
30
+ ### Global CLI Installation / Instalación CLI Global
170
31
 
171
- ```ts
172
- import {
173
- // Core
174
- ApiClient,
175
- Logger,
176
- Profiler,
177
- RetryPolicy,
178
- ResponseValidator,
179
- RequestCache,
180
- RateLimiter,
181
- RequestDeduplicator,
182
- ErrorBoundary,
183
-
184
- // Helpers
185
- DateUtils,
186
- StringUtils,
187
- Validator,
188
- EnvManager,
189
- StorageUtils,
190
- FileUploadHelper,
191
- StreamingHelper,
192
- WebSocketHelper,
193
- ArrayUtils,
194
- ObjectUtils,
195
- FormUtils,
196
- TimeUtils,
197
- EventEmitter,
198
- DiffUtils,
199
- PollingHelper,
200
- CryptoUtils,
201
- PaginationHelper,
202
- CacheManager,
203
- CompressionUtils,
204
-
205
- // Factory functions
206
- createLogger,
207
- createApiClient,
208
- createForm,
209
- createEventEmitter,
210
- createPoller,
211
- createPaginator,
212
- createCacheManager,
213
- } from "bytekit";
32
+ ```bash
33
+ npm install -g bytekit
34
+ # Then use / Luego usa:
35
+ sutils create users
36
+ sutils types https://api.example.com/users
214
37
  ```
215
38
 
216
- ## Quick Start / Inicio rápido
39
+ ### Basic Usage / Uso Básico
217
40
 
218
41
  ```ts
219
42
  import { ApiClient, createLogger, DateUtils, StringUtils } from "bytekit";
@@ -232,47 +55,39 @@ const users = await http.get<{ id: string; name: string }[]>("/users");
232
55
  const logger = createLogger({ namespace: "users-service", level: "info" });
233
56
  logger.info("Users synced", { count: users.length });
234
57
 
235
- logger.debug("Next sync ETA (days)", {
236
- etaDays: DateUtils.diffInDays(
237
- new Date(),
238
- DateUtils.add(new Date(), { days: 7 })
239
- ),
240
- });
241
-
242
58
  const slug = StringUtils.slugify("New Users – October 2024");
243
59
  ```
244
60
 
245
- **EN:** Import everything from the root entry, configure the ApiClient once, reuse helpers everywhere.
246
- **ES:** Importá desde la raíz, configurá el ApiClient una sola vez y reutilizá los helpers en todos tus servicios.
247
-
248
- ## Framework Examples / Ejemplos con Frameworks
61
+ ### Modular Imports / Importaciones Modulares
249
62
 
250
- **EN:** Bytekit is framework-agnostic and works seamlessly with React, Vue, Svelte, Angular, and more.
251
- **ES:** Bytekit es agnóstico al framework y funciona perfectamente con React, Vue, Svelte, Angular y más.
252
-
253
- ### 🎯 Works with / Compatible con
63
+ ```ts
64
+ // Import specific modules to reduce bundle size
65
+ // Importa módulos específicos para reducir el tamaño del bundle
254
66
 
255
- <div align="center">
67
+ // Core modules / Módulos core
68
+ import { ApiClient } from "bytekit/api-client";
69
+ import { Logger } from "bytekit/logger";
70
+ import { RetryPolicy } from "bytekit/retry-policy";
256
71
 
257
- **React** **Vue** **Svelte** • **Angular** • **Next.js** • **Nuxt** • **SvelteKit**
72
+ // Helper modules / Módulos helpers
73
+ import { DateUtils } from "bytekit/date-utils";
74
+ import { StringUtils } from "bytekit/string-utils";
75
+ import { ArrayUtils } from "bytekit/array-utils";
76
+ ```
258
77
 
259
- </div>
78
+ ## 🎯 Framework Support / Soporte de Frameworks
260
79
 
261
- ### 📚 Quick Examples / Ejemplos Rápidos
80
+ **EN:** Works seamlessly with React, Vue, Svelte, Angular, Next.js, Nuxt, SvelteKit, and more.
81
+ **ES:** Funciona perfectamente con React, Vue, Svelte, Angular, Next.js, Nuxt, SvelteKit y más.
262
82
 
263
- #### React
83
+ ### React Example / Ejemplo React
264
84
 
265
85
  ```jsx
266
86
  import { createApiClient } from "bytekit";
267
87
  import { useState, useEffect } from "react";
268
88
 
269
- function useApiClient(config) {
270
- const [client] = useState(() => createApiClient(config));
271
- return client;
272
- }
273
-
274
89
  function Users() {
275
- const client = useApiClient({ baseURL: "https://api.example.com" });
90
+ const client = createApiClient({ baseURL: "https://api.example.com" });
276
91
  const [users, setUsers] = useState([]);
277
92
 
278
93
  useEffect(() => {
@@ -289,2106 +104,112 @@ function Users() {
289
104
  }
290
105
  ```
291
106
 
292
- **[📖 Full React Guide](./docs/examples/react.md)** **[💻 Working Example](./examples/react-app)** • **[🚀 Try on CodeSandbox](https://codesandbox.io/p/devbox/bytekit-react-example-gr2k2j)**
293
-
294
- #### Vue 3
295
-
296
- ```vue
297
- <script setup>
298
- import { ref, onMounted } from "vue";
299
- import { createApiClient } from "bytekit";
300
-
301
- const client = createApiClient({ baseURL: "https://api.example.com" });
302
- const users = ref([]);
303
-
304
- onMounted(async () => {
305
- users.value = await client.get("/users");
306
- });
307
- </script>
308
-
309
- <template>
310
- <div v-for="user in users" :key="user.id">{{ user.name }}</div>
311
- </template>
312
- ```
313
-
314
- **[📖 Full Vue Guide](./docs/examples/vue.md)** • **[💻 Working Example](./examples/vue-app)** • **[🚀 Try on CodeSandbox](https://codesandbox.io/p/devbox/df26fs)**
315
-
316
- #### Svelte
317
-
318
- ```svelte
319
- <script>
320
- import { onMount } from 'svelte';
321
- import { createApiClient } from 'bytekit';
322
-
323
- const client = createApiClient({ baseURL: 'https://api.example.com' });
324
- let users = [];
325
-
326
- onMount(async () => {
327
- users = await client.get('/users');
328
- });
329
- </script>
330
-
331
- {#each users as user}
332
- <div>{user.name}</div>
333
- {/each}
334
- ```
335
-
336
- **[📖 Full Svelte Guide](./docs/examples/svelte.md)** • **[💻 Working Example](./examples/svelte-app)** • **[🚀 Try on CodeSandbox](https://codesandbox.io/p/devbox/lxvghg)**
337
-
338
- ### 🚀 Try the Examples / Probá los Ejemplos
339
-
340
- **EN:** Each example is a standalone Vite app ready to run:
341
- **ES:** Cada ejemplo es una app Vite lista para ejecutar:
342
-
343
- ```bash
344
- cd examples/react-app # or vue-app, svelte-app
345
- npm install
346
- npm run dev
347
- ```
348
-
349
- **[📁 View all examples](./examples)**
350
-
351
- ## API surface / Métodos expuestos
352
-
353
- **EN:** Complete reference of all exported methods and classes. Use `npm info bytekit` to see the full list.
354
- **ES:** Referencia completa de todos los métodos y clases exportados. Usa `npm info bytekit` para ver la lista completa.
355
-
356
- ### Core Modules / Módulos Core
357
-
358
- #### ApiClient
359
-
360
- ```ts
361
- class ApiClient {
362
- get<T>(url: string, options?: RequestOptions): Promise<T>;
363
- post<T>(url: string, body?: unknown, options?: RequestOptions): Promise<T>;
364
- put<T>(url: string, body?: unknown, options?: RequestOptions): Promise<T>;
365
- patch<T>(url: string, body?: unknown, options?: RequestOptions): Promise<T>;
366
- delete<T>(url: string, options?: RequestOptions): Promise<T>;
367
- getList<T>(
368
- url: string,
369
- options?: GetListOptions
370
- ): Promise<PaginatedResponse<T>>;
371
- request<T>(
372
- method: string,
373
- url: string,
374
- options?: RequestOptions
375
- ): Promise<T>;
376
- }
377
-
378
- function createApiClient(config: ApiClientConfig): ApiClient;
379
- class HttpError extends Error {
380
- status: number;
381
- body: unknown;
382
- }
383
- ```
384
-
385
- #### Logger
386
-
387
- ```ts
388
- class Logger {
389
- setLevel(level: LogLevel): void;
390
- child(namespace: string): Logger;
391
- debug(message: string, data?: unknown): void;
392
- info(message: string, data?: unknown): void;
393
- warn(message: string, data?: unknown): void;
394
- error(message: string, data?: unknown): void;
395
- log(level: LogLevel, message: string, data?: unknown): void;
396
- silent(): void;
397
- }
398
-
399
- function createLogger(config: LoggerConfig): Logger;
400
- const consoleTransportNode: Transport;
401
- const consoleTransportBrowser: Transport;
402
- ```
403
-
404
- #### Profiler
405
-
406
- ```ts
407
- class Profiler {
408
- start(label: string): void;
409
- end(label: string): number;
410
- summary(): ProfilerSummary[];
411
- }
412
- ```
413
-
414
- #### Debug Utilities
415
-
416
- ```ts
417
- function createStopwatch(options?: StopwatchOptions): Stopwatch;
418
- interface Stopwatch {
419
- stop(): number;
420
- elapsed(): number;
421
- log(data?: unknown): void;
422
- }
423
-
424
- async function withTiming<T>(label: string, fn: () => Promise<T>): Promise<T>;
425
- function measureSync<T>(
426
- label: string,
427
- fn: () => T
428
- ): { result: T; durationMs: number };
429
- async function measureAsync<T>(
430
- label: string,
431
- fn: () => Promise<T>
432
- ): Promise<{ result: T; durationMs: number }>;
433
- function captureDebug(label: string, data?: unknown): void;
434
- ```
435
-
436
- #### RetryPolicy
437
-
438
- ```ts
439
- class RetryPolicy {
440
- constructor(config: RetryPolicyConfig);
441
- async execute<T>(fn: () => Promise<T>): Promise<T>;
442
- getAttempts(): number;
443
- getRemainingAttempts(): number;
444
- }
445
-
446
- class CircuitBreaker {
447
- constructor(config: CircuitBreakerConfig);
448
- async execute<T>(fn: () => Promise<T>): Promise<T>;
449
- getState(): CircuitBreakerState;
450
- reset(): void;
451
- }
452
- ```
453
-
454
- #### ResponseValidator
455
-
456
- ```ts
457
- class ResponseValidator {
458
- static validate(data: unknown, schema: ValidationSchema): ValidationResult;
459
- static validateArray(
460
- data: unknown[],
461
- schema: ValidationSchema
462
- ): ValidationResult;
463
- }
464
-
465
- interface ValidationSchema {
466
- type: string;
467
- properties?: Record<string, ValidationSchema>;
468
- required?: string[];
469
- pattern?: RegExp;
470
- minimum?: number;
471
- maximum?: number;
472
- minLength?: number;
473
- maxLength?: number;
474
- }
475
- ```
476
-
477
- #### RequestCache
478
-
479
- ```ts
480
- class RequestCache {
481
- set(key: string, value: unknown, ttl?: number): void;
482
- get<T>(key: string): T | null;
483
- has(key: string): boolean;
484
- remove(key: string): void;
485
- clear(): void;
486
- invalidate(pattern: string): void;
487
- invalidatePattern(pattern: string): void;
488
- getStats(): CacheStats;
489
- }
490
- ```
491
-
492
- #### RateLimiter
493
-
494
- ```ts
495
- class RateLimiter {
496
- isAllowed(key: string): boolean;
497
- async waitForAllowance(key: string): Promise<void>;
498
- getStats(key: string): RateLimiterStats;
499
- reset(key?: string): void;
500
- }
501
-
502
- class SlidingWindowRateLimiter {
503
- isAllowed(key: string): boolean;
504
- async waitForAllowance(key: string): Promise<void>;
505
- getStats(key: string): RateLimiterStats;
506
- reset(key?: string): void;
507
- }
508
- ```
509
-
510
- #### RequestDeduplicator
511
-
512
- ```ts
513
- class RequestDeduplicator {
514
- async execute<T>(key: string, fn: () => Promise<T>): Promise<T>;
515
- getStats(): DeduplicatorStats;
516
- getInFlightCount(): number;
517
- clear(): void;
518
- }
519
- ```
520
-
521
- #### ErrorBoundary
522
-
523
- ```ts
524
- class ErrorBoundary {
525
- async execute<T>(fn: () => Promise<T>, context?: ErrorContext): Promise<T>;
526
- executeSync<T>(fn: () => T, context?: ErrorContext): T;
527
- wrap<T extends (...args: unknown[]) => Promise<unknown>>(fn: T): T;
528
- wrapSync<T extends (...args: unknown[]) => unknown>(fn: T): T;
529
- addHandler(handler: ErrorHandler): void;
530
- getErrorHistory(limit?: number): ErrorEntry[];
531
- createErrorReport(): ErrorReport;
532
- }
533
-
534
- function getGlobalErrorBoundary(config?: ErrorBoundaryConfig): ErrorBoundary;
535
-
536
- class AppError extends Error {
537
- code: string;
538
- context?: Record<string, unknown>;
539
- }
540
- class AppValidationError extends AppError {}
541
- class NotFoundError extends AppError {}
542
- class TimeoutError extends AppError {}
543
- class RateLimitError extends AppError {
544
- retryAfter?: number;
545
- }
546
- ```
547
-
548
- ### Helper Modules / Módulos Helpers
549
-
550
- #### DateUtils
551
-
552
- ```ts
553
- class DateUtils {
554
- static parse(date: Date | string | number): Date;
555
- static isValid(date: unknown): boolean;
556
- static toISODate(date: Date | string): string;
557
- static startOfDay(date: Date | string): Date;
558
- static endOfDay(date: Date | string): Date;
559
- static add(date: Date | string, duration: DateDuration): Date;
560
- static diff(
561
- from: Date | string,
562
- to: Date | string,
563
- options?: DiffOptions
564
- ): number;
565
- static diffInDays(
566
- from: Date | string,
567
- to: Date | string,
568
- options?: DiffOptions
569
- ): number;
570
- static isSameDay(date1: Date | string, date2: Date | string): boolean;
571
- static isBefore(date1: Date | string, date2: Date | string): boolean;
572
- static isAfter(date1: Date | string, date2: Date | string): boolean;
573
- static format(date: Date | string, locale?: string): string;
574
- }
575
- ```
576
-
577
- #### StringUtils
578
-
579
- ```ts
580
- class StringUtils {
581
- static removeDiacritics(str: string): string;
582
- static slugify(str: string, options?: SlugifyOptions): string;
583
- static compactWhitespace(str: string): string;
584
- static capitalize(str: string): string;
585
- static capitalizeWords(str: string): string;
586
- static truncate(
587
- str: string,
588
- length: number,
589
- options?: TruncateOptions
590
- ): string;
591
- static mask(str: string, options?: MaskOptions): string;
592
- static interpolate(
593
- template: string,
594
- values: Record<string, unknown>,
595
- options?: InterpolateOptions
596
- ): string;
597
- static initials(str: string, limit?: number): string;
598
- static toQueryString(
599
- obj: Record<string, unknown>,
600
- options?: QueryStringOptions
601
- ): string;
602
- }
603
- ```
604
-
605
- #### Validator
606
-
607
- ```ts
608
- class Validator {
609
- static isEmail(email: string): boolean;
610
- static isEmpty(value: unknown): boolean;
611
- static minLength(value: string, min: number): boolean;
612
- static maxLength(value: string, max: number): boolean;
613
- static matches(value: string, pattern: RegExp): boolean;
614
- static isUrl(url: string): boolean;
615
- static isInternationalPhone(phone: string): boolean;
616
- static isPhoneE164(phone: string): boolean;
617
- static isUUIDv4(uuid: string): boolean;
618
- static isLocalPhone(phone: string, locale?: string): boolean;
619
- static isDni(dni: string, locale?: string): boolean;
620
- static isCuit(cuit: string): boolean;
621
- static isCbu(cbu: string): boolean;
622
- static isStrongPassword(
623
- password: string,
624
- options?: PasswordOptions
625
- ): boolean;
626
- static isDateRange(
627
- date: Date | string,
628
- from: Date | string,
629
- to: Date | string
630
- ): boolean;
631
- static isOneTimeCode(code: string, length?: number): boolean;
632
- }
633
- ```
634
-
635
- #### EnvManager
636
-
637
- ```ts
638
- class EnvManager {
639
- get(key: string, defaultValue?: string): string | undefined;
640
- require(key: string): string;
641
- isProd(): boolean;
642
- isDev(): boolean;
643
- }
644
- ```
645
-
646
- #### StorageUtils
647
-
648
- ```ts
649
- class StorageUtils {
650
- constructor(storage?: Storage);
651
- set<T>(key: string, value: T, ttl?: number): void;
652
- get<T>(key: string): T | null;
653
- remove(key: string): void;
654
- clear(): void;
655
- has(key: string): boolean;
656
- }
657
- ```
658
-
659
- #### FileUploadHelper
660
-
661
- ```ts
662
- class FileUploadHelper {
663
- static validateFile(
664
- file: File,
665
- options?: FileValidationOptions
666
- ): FileValidationResult;
667
- static async uploadFile(
668
- file: File,
669
- url: string,
670
- options?: UploadOptions
671
- ): Promise<UploadResponse>;
672
- static async uploadChunked(
673
- file: File,
674
- url: string,
675
- options?: ChunkedUploadOptions
676
- ): Promise<UploadResponse>;
677
- }
678
- ```
679
-
680
- #### StreamingHelper
681
-
682
- ```ts
683
- class StreamingHelper {
684
- static async streamJsonLines<T>(
685
- url: string,
686
- options?: StreamOptions<T>
687
- ): Promise<StreamResult<T>>;
688
- static streamSSE<T>(
689
- url: string,
690
- options?: SSEOptions<T>
691
- ): SSESubscription<T>;
692
- static async downloadStream(
693
- url: string,
694
- options?: DownloadOptions
695
- ): Promise<Blob>;
696
- }
697
- ```
698
-
699
- #### WebSocketHelper
700
-
701
- ```ts
702
- class WebSocketHelper {
703
- constructor(url: string, options?: WebSocketOptions);
704
- async connect(): Promise<void>;
705
- on<T>(event: string, listener: (data: T) => void): void;
706
- once<T>(event: string, listener: (data: T) => void): void;
707
- off(event: string, listener: Function): void;
708
- send<T>(event: string, data: T): void;
709
- async request<Req, Res>(event: string, data: Req): Promise<Res>;
710
- onError(listener: (error: Error) => void): void;
711
- close(): void;
712
- isConnected(): boolean;
713
- }
714
- ```
715
-
716
- #### ArrayUtils
717
-
718
- ```ts
719
- class ArrayUtils {
720
- static chunk<T>(array: T[], size: number): T[][];
721
- static flatten<T>(array: unknown[], depth?: number): T[];
722
- static unique<T>(array: T[], by?: (item: T) => unknown): T[];
723
- static shuffle<T>(array: T[]): T[];
724
- static random<T>(array: T[]): T;
725
- static randomN<T>(array: T[], n: number): T[];
726
- static zip<T>(...arrays: T[][]): T[][];
727
- static unzip<T>(array: T[][]): T[][];
728
- static difference<T>(array1: T[], array2: T[]): T[];
729
- static intersection<T>(array1: T[], array2: T[]): T[];
730
- static union<T>(array1: T[], array2: T[]): T[];
731
- static partition<T>(
732
- array: T[],
733
- predicate: (item: T) => boolean
734
- ): [T[], T[]];
735
- static sum(array: number[]): number;
736
- static average(array: number[]): number;
737
- static min(array: number[]): number;
738
- static max(array: number[]): number;
739
- static range(start: number, end: number, step?: number): number[];
740
- static rotate<T>(array: T[], steps: number): T[];
741
- static transpose<T>(array: T[][]): T[][];
742
- }
743
- ```
744
-
745
- #### ObjectUtils
746
-
747
- ```ts
748
- class ObjectUtils {
749
- static isEmpty(obj: unknown): boolean;
750
- static deepClone<T>(obj: T): T;
751
- static merge<T>(...objects: Partial<T>[]): T;
752
- static deepMerge<T>(...objects: Partial<T>[]): T;
753
- static pick<T>(obj: T, keys: (keyof T)[]): Partial<T>;
754
- static omit<T>(obj: T, keys: (keyof T)[]): Partial<T>;
755
- static get<T>(obj: unknown, path: string): T | undefined;
756
- static set<T>(obj: T, path: string, value: unknown): T;
757
- static flatten<T>(obj: T, prefix?: string): Record<string, unknown>;
758
- static unflatten(obj: Record<string, unknown>): Record<string, unknown>;
759
- static filter<T>(
760
- obj: T,
761
- predicate: (key: string, value: unknown) => boolean
762
- ): Partial<T>;
763
- static mapValues<T>(obj: T, mapper: (value: unknown) => unknown): T;
764
- static hasKeys<T>(obj: T, keys: (keyof T)[]): boolean;
765
- static invert<T>(obj: Record<string, T>): Record<T, string>;
766
- static groupBy<T>(array: T[], key: keyof T): Record<string, T[]>;
767
- static indexBy<T>(array: T[], key: keyof T): Record<string, T>;
768
- static deepEqual(obj1: unknown, obj2: unknown): boolean;
769
- static size(obj: Record<string, unknown>): number;
770
- static entries<T>(obj: T): [string, unknown][];
771
- static fromEntries(entries: [string, unknown][]): Record<string, unknown>;
772
- static fromKeys<T>(keys: string[], value: T): Record<string, T>;
773
- }
774
- ```
775
-
776
- #### FormUtils
777
-
778
- ```ts
779
- class FormUtils {
780
- constructor(config: FormConfig);
781
- setValue(field: string, value: unknown): void;
782
- getValue(field: string): unknown;
783
- getFieldError(field: string): string;
784
- touchField(field: string): void;
785
- isTouched(field: string): boolean;
786
- isDirty(field: string): boolean;
787
- async validateField(field: string): Promise<string | null>;
788
- async validate(): Promise<Record<string, string>>;
789
- async submit(): Promise<boolean>;
790
- getState(): FormState;
791
- createBinding(field: string): FieldBinding;
792
- reset(): void;
793
- serialize(): Record<string, unknown>;
794
- deserialize(data: Record<string, unknown>): void;
795
- }
107
+ **[📖 View More Framework Examples ](https://github.com/sebamar88/bytekit/wiki/Framework-Examples)**
796
108
 
797
- function createForm(config: FormConfig): FormUtils;
109
+ ## 📚 Complete Documentation / Documentación Completa
798
110
 
799
- class Validators {
800
- static required(value: unknown): boolean;
801
- static email(value: string): boolean;
802
- static minLength(value: string, min: number): boolean;
803
- static maxLength(value: string, max: number): boolean;
804
- static pattern(value: string, pattern: RegExp): boolean;
805
- static url(value: string): boolean;
806
- static match(value: string, other: string): boolean;
807
- }
808
- ```
111
+ **EN:** For detailed documentation of all 28 modules, visit our comprehensive GitHub Wiki.
112
+ **ES:** Para documentación detallada de todos los 28 módulos, visita nuestra GitHub Wiki completa.
809
113
 
810
- #### TimeUtils
114
+ ### 🔗 Quick Links by Category / Enlaces Rápidos por Categoría
811
115
 
812
- ```ts
813
- class TimeUtils {
814
- static now(): number;
815
- static sleep(ms: number): Promise<void>;
816
- static debounce<T extends (...args: unknown[]) => unknown>(
817
- fn: T,
818
- delay: number
819
- ): T;
820
- static throttle<T extends (...args: unknown[]) => unknown>(
821
- fn: T,
822
- delay: number
823
- ): T;
824
- static timeout<T>(promise: Promise<T>, ms: number): Promise<T>;
825
- static retry<T>(fn: () => Promise<T>, options?: RetryOptions): Promise<T>;
826
- }
827
- ```
116
+ #### 🔧 Core Modules (9) - Essential functionality / Funcionalidad esencial
117
+ - **[ApiClient](https://github.com/sebamar88/bytekit/wiki/ApiClient)** - Typed HTTP client with retries, localized errors, and custom fetch support
118
+ - **[Logger](https://github.com/sebamar88/bytekit/wiki/Logger)** - Structured logger with levels, namespaces, and transports for Node/browser
119
+ - **[Profiler](https://github.com/sebamar88/bytekit/wiki/Profiler)** - Profiler utilities and helpers
120
+ - **[RetryPolicy](https://github.com/sebamar88/bytekit/wiki/RetryPolicy)** - RetryPolicy utilities and helpers
121
+ - **[ResponseValidator](https://github.com/sebamar88/bytekit/wiki/ResponseValidator)** - ResponseValidator utilities and helpers
122
+ - **[RequestCache](https://github.com/sebamar88/bytekit/wiki/RequestCache)** - RequestCache utilities and helpers
123
+ - **[RateLimiter](https://github.com/sebamar88/bytekit/wiki/RateLimiter)** - RateLimiter utilities and helpers
124
+ - **[RequestDeduplicator](https://github.com/sebamar88/bytekit/wiki/RequestDeduplicator)** - RequestDeduplicator utilities and helpers
125
+ - **[ErrorBoundary](https://github.com/sebamar88/bytekit/wiki/ErrorBoundary)** - ErrorBoundary utilities and helpers
828
126
 
829
- #### EventEmitter
127
+ #### 🛠️ Helper Modules (12) - Common utilities / Utilidades comunes
128
+ - **[DateUtils](https://github.com/sebamar88/bytekit/wiki/DateUtils)** - Safe date parsing, manipulation, and formatting utilities
129
+ - **[StringUtils](https://github.com/sebamar88/bytekit/wiki/StringUtils)** - Text processing utilities: slugify, capitalize, mask, interpolate
130
+ - **[Validator](https://github.com/sebamar88/bytekit/wiki/Validator)** - Validation utilities for emails, phones, passwords, and more
131
+ - **[EnvManager](https://github.com/sebamar88/bytekit/wiki/EnvManager)** - EnvManager utilities and helpers
132
+ - **[StorageUtils](https://github.com/sebamar88/bytekit/wiki/StorageUtils)** - StorageUtils utilities and helpers
133
+ - **[FileUploadHelper](https://github.com/sebamar88/bytekit/wiki/FileUploadHelper)** - FileUploadHelper utilities and helpers
134
+ - **[StreamingHelper](https://github.com/sebamar88/bytekit/wiki/StreamingHelper)** - StreamingHelper utilities and helpers
135
+ - **[WebSocketHelper](https://github.com/sebamar88/bytekit/wiki/WebSocketHelper)** - WebSocketHelper utilities and helpers
136
+ - **[ArrayUtils](https://github.com/sebamar88/bytekit/wiki/ArrayUtils)** - Array manipulation utilities: chunk, flatten, unique, shuffle, zip
137
+ - **[ObjectUtils](https://github.com/sebamar88/bytekit/wiki/ObjectUtils)** - Object manipulation utilities: merge, pick, omit, flatten, groupBy
138
+ - **[FormUtils](https://github.com/sebamar88/bytekit/wiki/FormUtils)** - FormUtils utilities and helpers
139
+ - **[TimeUtils](https://github.com/sebamar88/bytekit/wiki/TimeUtils)** - TimeUtils utilities and helpers
830
140
 
831
- ```ts
832
- class EventEmitter<
833
- Events extends Record<string, unknown> = Record<string, unknown>
834
- > {
835
- on<K extends keyof Events>(
836
- event: K,
837
- listener: EventListener<Events[K]>
838
- ): this;
839
- once<K extends keyof Events>(
840
- event: K,
841
- listener: EventListener<Events[K]>
842
- ): this;
843
- off<K extends keyof Events>(
844
- event: K,
845
- listener: EventListener<Events[K]>
846
- ): this;
847
- removeAllListeners<K extends keyof Events>(event?: K): this;
848
- async emit<K extends keyof Events>(
849
- event: K,
850
- data: Events[K]
851
- ): Promise<boolean>;
852
- emitSync<K extends keyof Events>(event: K, data: Events[K]): boolean;
853
- onError(listener: EventListenerWithError): this;
854
- listenerCount<K extends keyof Events>(event: K): number;
855
- getListeners<K extends keyof Events>(event: K): EventListener<Events[K]>[];
856
- eventNames(): (keyof Events)[];
857
- setMaxListeners(n: number): this;
858
- getMaxListeners(): number;
859
- }
141
+ #### ⚡ Utility Modules (7) - Advanced features / Características avanzadas
142
+ - **[EventEmitter](https://github.com/sebamar88/bytekit/wiki/EventEmitter)** - EventEmitter utilities and helpers
143
+ - **[DiffUtils](https://github.com/sebamar88/bytekit/wiki/DiffUtils)** - DiffUtils utilities and helpers
144
+ - **[PollingHelper](https://github.com/sebamar88/bytekit/wiki/PollingHelper)** - PollingHelper utilities and helpers
145
+ - **[CryptoUtils](https://github.com/sebamar88/bytekit/wiki/CryptoUtils)** - Token/UUID generation, base64 encoding, hashing, and HMAC
146
+ - **[PaginationHelper](https://github.com/sebamar88/bytekit/wiki/PaginationHelper)** - PaginationHelper utilities and helpers
147
+ - **[CacheManager](https://github.com/sebamar88/bytekit/wiki/CacheManager)** - Multi-tier cache with TTL, LRU eviction, and statistics
148
+ - **[CompressionUtils](https://github.com/sebamar88/bytekit/wiki/CompressionUtils)** - CompressionUtils utilities and helpers
860
149
 
861
- function createEventEmitter<
862
- Events extends Record<string, unknown> = Record<string, unknown>
863
- >(options?: EventEmitterOptions): EventEmitter<Events>;
864
- ```
150
+ **[🏠 Browse Full Wiki Index →](https://github.com/sebamar88/bytekit/wiki)**
865
151
 
866
- #### DiffUtils
152
+ ## 🌟 Popular Use Cases / Casos de Uso Populares
867
153
 
154
+ ### HTTP Client with Retries / Cliente HTTP con Reintentos
868
155
  ```ts
869
- class DiffUtils {
870
- static diff(
871
- old: Record<string, unknown>,
872
- new_: Record<string, unknown>
873
- ): DiffResult;
874
- static createPatch(
875
- old: Record<string, unknown>,
876
- new_: Record<string, unknown>
877
- ): Patch[];
878
- static applyPatch<T>(obj: T, patches: Patch[]): T;
879
- static deepEqual(obj1: unknown, obj2: unknown): boolean;
880
- }
156
+ const api = new ApiClient({
157
+ baseUrl: "https://api.example.com",
158
+ retryPolicy: { maxAttempts: 3, initialDelayMs: 100 },
159
+ circuitBreaker: { failureThreshold: 5 }
160
+ });
881
161
 
882
- interface Patch {
883
- op: "add" | "remove" | "replace";
884
- path: string;
885
- value?: unknown;
886
- }
162
+ const users = await api.get("/users");
887
163
  ```
888
164
 
889
- #### PollingHelper
890
-
165
+ ### Structured Logging / Logging Estructurado
891
166
  ```ts
892
- class PollingHelper {
893
- constructor(fn: () => Promise<unknown>, options?: PollingOptions);
894
- async start(): Promise<PollingResult>;
895
- stop(): void;
896
- }
897
-
898
- function createPoller(
899
- fn: () => Promise<unknown>,
900
- options?: PollingOptions
901
- ): PollingHelper;
902
-
903
- interface PollingResult {
904
- success: boolean;
905
- attempts: number;
906
- lastResult: unknown;
907
- totalTimeMs: number;
908
- }
167
+ const logger = createLogger({ namespace: "app", level: "info" });
168
+ logger.info("User created", { userId: 123, email: "user@example.com" });
909
169
  ```
910
170
 
911
- #### CryptoUtils
912
-
171
+ ### Date & String Utilities / Utilidades de Fecha y String
913
172
  ```ts
914
- class CryptoUtils {
915
- static generateToken(bytes?: number): string;
916
- static generateUUID(): string;
917
- static base64Encode(str: string): string;
918
- static base64Decode(str: string): string;
919
- static base64UrlEncode(str: string): string;
920
- static base64UrlDecode(str: string): string;
921
- static async hash(str: string): Promise<string>;
922
- static async verifyHash(str: string, hash: string): Promise<boolean>;
923
- static constantTimeCompare(a: string, b: string): boolean;
924
- static async hmac(message: string, secret: string): Promise<string>;
925
- }
173
+ const formatted = DateUtils.format(new Date(), "es-AR");
174
+ const slug = StringUtils.slugify("Hello World! 🌍");
175
+ const masked = StringUtils.mask("1234567890", { start: 4, end: 2 });
926
176
  ```
927
177
 
928
- #### PaginationHelper
929
-
178
+ ### Array & Object Manipulation / Manipulación de Arrays y Objetos
930
179
  ```ts
931
- class PaginationHelper {
932
- constructor(items: unknown[], options?: PaginationOptions);
933
- getCurrentPage(): unknown[];
934
- next(): void;
935
- previous(): void;
936
- goToPage(page: number): void;
937
- getState(): PaginationState;
938
- }
939
-
940
- function createPaginator(
941
- items: unknown[],
942
- options?: PaginationOptions
943
- ): PaginationHelper;
944
-
945
- interface PaginationState {
946
- currentPage: number;
947
- pageSize: number;
948
- total: number;
949
- totalPages: number;
950
- hasNextPage: boolean;
951
- hasPreviousPage: boolean;
952
- offset: number;
953
- limit: number;
954
- }
180
+ const chunks = ArrayUtils.chunk([1, 2, 3, 4, 5], 2); // [[1,2], [3,4], [5]]
181
+ const picked = ObjectUtils.pick(user, ["id", "name", "email"]);
182
+ const grouped = ObjectUtils.groupBy(users, "department");
955
183
  ```
956
184
 
957
- #### CacheManager
958
-
959
- ```ts
960
- class CacheManager {
961
- constructor(options?: CacheManagerOptions);
962
- set<T>(key: string, value: T, ttl?: number): void;
963
- get<T>(key: string): T | null;
964
- has(key: string): boolean;
965
- remove(key: string): void;
966
- clear(): void;
967
- async getOrCompute<T>(
968
- key: string,
969
- fn: () => Promise<T>,
970
- ttl?: number
971
- ): Promise<T>;
972
- invalidatePattern(pattern: string): void;
973
- getStats(): CacheStats;
974
- }
185
+ ## 🚀 Live Examples / Ejemplos en Vivo
975
186
 
976
- function createCacheManager(options?: CacheManagerOptions): CacheManager;
977
-
978
- interface CacheStats {
979
- hits: number;
980
- misses: number;
981
- hitRate: number;
982
- size: number;
983
- maxSize: number;
984
- }
985
- ```
187
+ **EN:** Try bytekit in your browser with these interactive examples:
188
+ **ES:** Prueba bytekit en tu navegador con estos ejemplos interactivos:
986
189
 
987
- #### CompressionUtils
190
+ - **[React Example](https://codesandbox.io/p/devbox/bytekit-react-example-gr2k2j)** - Complete React app with ApiClient
191
+ - **[Vue Example](https://codesandbox.io/p/devbox/df26fs)** - Vue 3 composition API usage
192
+ - **[Svelte Example](https://codesandbox.io/p/devbox/lxvghg)** - Svelte integration example
988
193
 
989
- ```ts
990
- class CompressionUtils {
991
- static compress(str: string): string;
992
- static decompress(compressed: string): string;
993
- static base64Encode(str: string): string;
994
- static base64Decode(str: string): string;
995
- static base64UrlEncode(str: string): string;
996
- static base64UrlDecode(str: string): string;
997
- static serializeCompressed(obj: unknown): string;
998
- static deserializeCompressed(compressed: string): unknown;
999
- static getCompressionRatio(original: string, compressed: string): number;
1000
- static minifyJSON(json: string): string;
1001
- static prettyJSON(json: string, indent?: number): string;
1002
- static async gzip(str: string): Promise<Buffer | string>;
1003
- static async gunzip(data: Buffer | string): Promise<string>;
1004
- static async deflate(str: string): Promise<Buffer | string>;
1005
- static async inflate(data: Buffer | string): Promise<string>;
1006
- static getSize(str: string): number;
1007
- static formatBytes(bytes: number, decimals?: number): string;
1008
- }
1009
- ```
194
+ **[📁 View Local Examples →](https://github.com/sebamar88/bytekit/tree/main/examples)**
1010
195
 
1011
- ## API surface (pnpm info) / Métodos expuestos
196
+ ## 🔗 Links / Enlaces
1012
197
 
1013
- `pnpm info bytekit readme` ahora lista todos los exports públicos:
198
+ - **[📦 NPM Package](https://www.npmjs.com/package/bytekit)** - Install and version info
199
+ - **[📚 Full Documentation Wiki](https://github.com/sebamar88/bytekit/wiki)** - Complete API reference
200
+ - **[🚀 Live Examples](https://github.com/sebamar88/bytekit/tree/main/examples)** - Working code samples
201
+ - **[📋 Issues & Support](https://github.com/sebamar88/bytekit/issues)** - Bug reports and feature requests
202
+ - **[🔄 Changelog](https://github.com/sebamar88/bytekit/blob/main/CHANGELOG.md)** - Version history
1014
203
 
1015
- ## ApiClient Details / Detalles del ApiClient
204
+ ## 🤝 Contributing / Contribuir
1016
205
 
1017
- - `baseUrl`: **EN** required prefix for relative endpoints. **ES** prefijo requerido para endpoints relativos.
1018
- - `defaultHeaders`: **EN** shared headers merged per request. **ES** cabeceras comunes que se combinan en cada request.
1019
- - `locale` + `errorMessages`: **EN** localized HTTP errors. **ES** mensajes localizados por código HTTP.
1020
- - `fetchImpl`: **EN** inject your own fetch (tests, custom environments). **ES** inyectá tu propio `fetch` (tests o entornos custom).
1021
- - `retryPolicy`: **EN** configure automatic retries with exponential backoff. **ES** configura reintentos automáticos con backoff exponencial.
1022
- - `circuitBreaker`: **EN** configure circuit breaker to prevent cascading failures. **ES** configura circuit breaker para evitar fallos en cascada.
206
+ **EN:** Contributions are welcome! Please read our contributing guidelines and feel free to submit issues and pull requests.
207
+ **ES:** ¡Las contribuciones son bienvenidas! Lee nuestras guías de contribución y no dudes en enviar issues y pull requests.
1023
208
 
1024
- Each `request` (and `get`, `post`, `put`, `patch`, `delete`) accepts / Cada request acepta:
209
+ ## 📄 License / Licencia
1025
210
 
1026
- - `searchParams`: **EN** serializes to URLSearchParams. **ES** se serializa automáticamente.
1027
- - `body`: **EN** strings, serializable objects, or `FormData`. **ES** strings, objetos serializables o `FormData`.
1028
- - `errorLocale`: **EN** override language per request. **ES** forzá un idioma específico.
1029
- - Native `RequestInit` fields (`headers`, `signal`, etc.).
211
+ MIT © [Sebastián Martinez](https://github.com/sebamar88)
1030
212
 
1031
- ```ts
1032
- import { HttpError } from "bytekit";
1033
-
1034
- try {
1035
- await http.get("/users");
1036
- } catch (error) {
1037
- if (error instanceof HttpError) {
1038
- console.error("Server error", error.status, error.body);
1039
- }
1040
- }
1041
- ```
1042
-
1043
- ### Paginated Lists / Listados Paginados
1044
-
1045
- - **getList**: **EN** fetch paginated data with built-in support for `pagination`, `sort`, and `filters`. Returns a typed `PaginatedResponse` with metadata. **ES** obtiene datos paginados con soporte para `pagination`, `sort` y `filters`. Devuelve `PaginatedResponse` con metadatos.
1046
-
1047
- ```ts
1048
- import { ApiClient } from "bytekit";
1049
-
1050
- const api = new ApiClient({ baseUrl: "https://api.example.com" });
1051
-
1052
- // Fetch first page with 10 items per page
1053
- const response = await api.getList<User>("/users", {
1054
- pagination: { page: 1, limit: 10 },
1055
- sort: { field: "name", order: "asc" },
1056
- filters: { status: "active" },
1057
- });
1058
-
1059
- console.log(response.data); // User[]
1060
- console.log(response.pagination);
1061
- // {
1062
- // page: 1,
1063
- // limit: 10,
1064
- // total: 42,
1065
- // totalPages: 5,
1066
- // hasNextPage: true,
1067
- // hasPreviousPage: false,
1068
- // }
1069
-
1070
- // Fetch with custom filters
1071
- const filtered = await api.getList<User>("/users", {
1072
- pagination: { page: 2, limit: 20 },
1073
- sort: { field: "createdAt", order: "desc" },
1074
- filters: { role: "admin", department: "engineering" },
1075
- });
1076
- ```
1077
-
1078
- ## Advanced Features / Características Avanzadas
1079
-
1080
- ### Retry Policy & Circuit Breaker
1081
-
1082
- - **RetryPolicy**: **EN** automatic retry with exponential backoff for transient failures. **ES** reintentos automáticos con backoff exponencial para fallos transitorios.
1083
- - **CircuitBreaker**: **EN** prevent cascading failures by stopping requests when service is down. **ES** evita fallos en cascada deteniendo requests cuando el servicio está caído.
1084
-
1085
- ```ts
1086
- import { ApiClient } from "bytekit";
1087
-
1088
- const api = new ApiClient({
1089
- baseUrl: "https://api.example.com",
1090
- retryPolicy: {
1091
- maxAttempts: 3,
1092
- initialDelayMs: 100,
1093
- backoffMultiplier: 2,
1094
- },
1095
- circuitBreaker: {
1096
- failureThreshold: 5,
1097
- successThreshold: 2,
1098
- timeoutMs: 60000,
1099
- },
1100
- });
1101
-
1102
- // Requests automatically retry and respect circuit breaker state
1103
- const data = await api.get("/users");
1104
- ```
1105
-
1106
- ### Response Validation
1107
-
1108
- - **ResponseValidator**: **EN** validate API responses against schemas before using them. **ES** valida respuestas de API contra esquemas antes de usarlas.
1109
-
1110
- ```ts
1111
- import { ApiClient, ValidationSchema } from "bytekit";
1112
-
1113
- const userSchema: ValidationSchema = {
1114
- type: "object",
1115
- properties: {
1116
- id: { type: "number", required: true },
1117
- email: { type: "string", pattern: /.+@.+\..+/ },
1118
- age: { type: "number", minimum: 0, maximum: 150 },
1119
- },
1120
- };
1121
-
1122
- const users = await api.get<User[]>("/users", {
1123
- validateResponse: {
1124
- type: "array",
1125
- items: userSchema,
1126
- },
1127
- });
1128
- ```
1129
-
1130
- ### File Upload Helper
1131
-
1132
- - **FileUploadHelper**: **EN** upload files with progress tracking, chunking, and retry support. **ES** sube archivos con seguimiento de progreso, chunking y reintentos.
1133
-
1134
- ```ts
1135
- import { FileUploadHelper } from "bytekit";
1136
-
1137
- const file = document.querySelector<HTMLInputElement>("#file")?.files?.[0];
1138
- if (file) {
1139
- const validation = FileUploadHelper.validateFile(file, {
1140
- maxSize: 50 * 1024 * 1024, // 50MB
1141
- allowedTypes: ["image/jpeg", "image/png"],
1142
- });
1143
-
1144
- if (validation.valid) {
1145
- const response = await FileUploadHelper.uploadFile(
1146
- file,
1147
- "/api/upload",
1148
- {
1149
- chunkSize: 5 * 1024 * 1024, // 5MB chunks
1150
- onProgress: (progress) => {
1151
- console.log(`${progress.percentage}% uploaded`);
1152
- },
1153
- }
1154
- );
1155
- }
1156
- }
1157
- ```
1158
-
1159
- ### Streaming Helper
1160
-
1161
- - **StreamingHelper**: **EN** stream JSON lines, Server-Sent Events, or download files with progress. **ES** transmite JSON lines, Server-Sent Events o descarga archivos con progreso.
1162
-
1163
- ```ts
1164
- import { StreamingHelper } from "bytekit";
1165
-
1166
- // Stream JSON lines (NDJSON)
1167
- const { data, complete } = await StreamingHelper.streamJsonLines<User>(
1168
- "/api/users/stream",
1169
- {
1170
- onChunk: (line) => console.log("Received:", line),
1171
- onComplete: () => console.log("Stream complete"),
1172
- }
1173
- );
1174
-
1175
- // Stream Server-Sent Events
1176
- const sse = StreamingHelper.streamSSE<Message>("/api/messages", {
1177
- eventType: "message",
1178
- });
1179
-
1180
- const unsubscribe = sse.subscribe((message) => {
1181
- console.log("New message:", message);
1182
- });
1183
-
1184
- // Download with progress
1185
- const blob = await StreamingHelper.downloadStream("/api/export.csv", {
1186
- onProgress: (percentage) => console.log(`Downloaded: ${percentage}%`),
1187
- });
1188
- ```
1189
-
1190
- ### WebSocket Helper
1191
-
1192
- - **WebSocketHelper**: **EN** manage WebSocket connections with auto-reconnect, heartbeat, and typed messages. **ES** gestiona conexiones WebSocket con reconexión automática, heartbeat y mensajes tipados.
1193
-
1194
- ```ts
1195
- import { WebSocketHelper } from "bytekit";
1196
-
1197
- const ws = new WebSocketHelper("wss://api.example.com/ws", {
1198
- reconnect: true,
1199
- maxReconnectAttempts: 5,
1200
- heartbeatIntervalMs: 30000,
1201
- });
1202
-
1203
- await ws.connect();
1204
-
1205
- // Subscribe to messages
1206
- ws.on<{ userId: string; text: string }>("message", (data) => {
1207
- console.log(`${data.userId}: ${data.text}`);
1208
- });
1209
-
1210
- // Send messages
1211
- ws.send("message", { text: "Hello!" });
1212
-
1213
- // Request-response pattern
1214
- const response = await ws.request<{ query: string }, { result: string }>(
1215
- "query",
1216
- { query: "SELECT * FROM users" }
1217
- );
1218
-
1219
- // Handle errors
1220
- ws.onError((error) => console.error("WebSocket error:", error));
1221
-
1222
- // Close connection
1223
- ws.close();
1224
- ```
1225
-
1226
- ### Request Caching
1227
-
1228
- - **RequestCache**: **EN** cache HTTP responses with TTL and stale-while-revalidate support. **ES** cachea respuestas HTTP con TTL y soporte para stale-while-revalidate.
1229
-
1230
- ```ts
1231
- import { RequestCache } from "bytekit";
1232
-
1233
- const cache = new RequestCache({
1234
- ttl: 5 * 60 * 1000, // 5 minutes
1235
- staleWhileRevalidate: 60 * 1000, // 1 minute
1236
- });
1237
-
1238
- // Cache a response
1239
- cache.set("/users", users);
1240
-
1241
- // Retrieve from cache
1242
- const cached = cache.get("/users");
1243
-
1244
- // Check if stale but still valid
1245
- if (cache.isStale("/users")) {
1246
- // Revalidate in background
1247
- }
1248
-
1249
- // Invalidate specific entry
1250
- cache.invalidate("/users");
1251
-
1252
- // Invalidate by pattern
1253
- cache.invalidatePattern("/users/*");
1254
-
1255
- // Get statistics
1256
- const stats = cache.getStats();
1257
- console.log(`Hit rate: ${stats.hitRate * 100}%`);
1258
- ```
1259
-
1260
- ### Rate Limiting
1261
-
1262
- - **RateLimiter**: **EN** token bucket rate limiter for smooth request throttling. **ES** limitador de tasa con token bucket para throttling suave.
1263
- - **SlidingWindowRateLimiter**: **EN** sliding window rate limiter for precise rate control. **ES** limitador de ventana deslizante para control preciso de tasa.
1264
-
1265
- ```ts
1266
- import { RateLimiter, SlidingWindowRateLimiter } from "bytekit";
1267
-
1268
- // Token bucket limiter (allows bursts)
1269
- const limiter = new RateLimiter({
1270
- maxRequests: 100,
1271
- windowMs: 60 * 1000, // 1 minute
1272
- });
1273
-
1274
- if (limiter.isAllowed("https://api.example.com/users")) {
1275
- // Make request
1276
- }
1277
-
1278
- // Wait for allowance if rate limited
1279
- await limiter.waitForAllowance("https://api.example.com/users");
1280
-
1281
- // Get stats
1282
- const stats = limiter.getStats("https://api.example.com/users");
1283
- console.log(`Remaining: ${stats.remaining}/${stats.limit}`);
1284
-
1285
- // Sliding window limiter (more accurate)
1286
- const slidingLimiter = new SlidingWindowRateLimiter({
1287
- maxRequests: 100,
1288
- windowMs: 60 * 1000,
1289
- });
1290
-
1291
- if (slidingLimiter.isAllowed("https://api.example.com/users")) {
1292
- // Make request
1293
- }
1294
- ```
1295
-
1296
- ### Request Deduplication
1297
-
1298
- - **RequestDeduplicator**: **EN** deduplicate in-flight requests to avoid redundant API calls. **ES** deduplica requests en vuelo para evitar llamadas redundantes.
1299
-
1300
- ```ts
1301
- import { RequestDeduplicator } from "bytekit";
1302
-
1303
- const dedup = new RequestDeduplicator();
1304
-
1305
- // Multiple consumers of the same request share the same response
1306
- const [users1, users2] = await Promise.all([
1307
- dedup.execute("/users", () => api.get("/users")),
1308
- dedup.execute("/users", () => api.get("/users")), // Deduplicated!
1309
- ]);
1310
-
1311
- // Different requests execute separately
1312
- const [users, posts] = await Promise.all([
1313
- dedup.execute("/users", () => api.get("/users")),
1314
- dedup.execute("/posts", () => api.get("/posts")),
1315
- ]);
1316
-
1317
- // Get statistics
1318
- const stats = dedup.getStats();
1319
- console.log(`Deduplication rate: ${stats.deduplicationRate * 100}%`);
1320
-
1321
- // Check in-flight requests
1322
- console.log(`In-flight: ${dedup.getInFlightCount()}`);
1323
- ```
1324
-
1325
- ### Object Utilities
1326
-
1327
- - **ObjectUtils**: **EN** everyday object manipulation utilities (isEmpty, deepClone, merge, pick, omit, flatten, groupBy, etc.). **ES** utilidades cotidianas para manipular objetos.
1328
-
1329
- ```ts
1330
- import { ObjectUtils } from "bytekit";
1331
-
1332
- // Check if empty
1333
- ObjectUtils.isEmpty(null); // true
1334
- ObjectUtils.isEmpty({}); // true
1335
- ObjectUtils.isEmpty([1, 2]); // false
1336
-
1337
- // Deep clone
1338
- const original = { a: { b: 1 } };
1339
- const cloned = ObjectUtils.deepClone(original);
1340
-
1341
- // Merge objects
1342
- const merged = ObjectUtils.merge({ a: 1 }, { b: 2 }, { c: 3 });
1343
- // { a: 1, b: 2, c: 3 }
1344
-
1345
- // Pick/omit keys
1346
- const user = {
1347
- id: 1,
1348
- name: "John",
1349
- email: "john@example.com",
1350
- password: "secret",
1351
- };
1352
- const safe = ObjectUtils.omit(user, ["password"]);
1353
- // { id: 1, name: "John", email: "john@example.com" }
1354
-
1355
- // Nested access with dot notation
1356
- const config = { db: { host: "localhost", port: 5432 } };
1357
- const host = ObjectUtils.get(config, "db.host"); // "localhost"
1358
- ObjectUtils.set(config, "db.ssl", true);
1359
-
1360
- // Flatten/unflatten
1361
- const flat = ObjectUtils.flatten({ a: { b: { c: 1 } } });
1362
- // { "a.b.c": 1 }
1363
-
1364
- // Group and index arrays
1365
- const users = [
1366
- { id: 1, role: "admin" },
1367
- { id: 2, role: "user" },
1368
- { id: 3, role: "admin" },
1369
- ];
1370
- const byRole = ObjectUtils.groupBy(users, "role");
1371
- const byId = ObjectUtils.indexBy(users, "id");
1372
-
1373
- // Filter and map
1374
- const filtered = ObjectUtils.filter(
1375
- user,
1376
- (_, value) => typeof value === "string"
1377
- );
1378
- const doubled = ObjectUtils.mapValues({ a: 1, b: 2 }, (v) => v * 2);
1379
-
1380
- // Deep equality
1381
- ObjectUtils.deepEqual({ a: 1 }, { a: 1 }); // true
1382
- ```
1383
-
1384
- ### Array Utilities
1385
-
1386
- - **ArrayUtils**: **EN** everyday array manipulation utilities (chunk, flatten, unique, shuffle, zip, partition, etc.). **ES** utilidades cotidianas para manipular arrays.
1387
-
1388
- ```ts
1389
- import { ArrayUtils } from "bytekit";
1390
-
1391
- // Chunk array into smaller pieces
1392
- ArrayUtils.chunk([1, 2, 3, 4, 5], 2); // [[1, 2], [3, 4], [5]]
1393
-
1394
- // Flatten nested arrays
1395
- ArrayUtils.flatten(
1396
- [
1397
- [1, 2],
1398
- [3, [4, 5]],
1399
- ],
1400
- 2
1401
- ); // [1, 2, 3, 4, 5]
1402
-
1403
- // Get unique values
1404
- ArrayUtils.unique([1, 2, 2, 3, 3, 3]); // [1, 2, 3]
1405
- ArrayUtils.unique([{ id: 1 }, { id: 2 }, { id: 1 }], (item) => item.id); // [{ id: 1 }, { id: 2 }]
1406
-
1407
- // Shuffle and random selection
1408
- const shuffled = ArrayUtils.shuffle([1, 2, 3, 4, 5]);
1409
- const random = ArrayUtils.random([1, 2, 3, 4, 5]);
1410
- const randomN = ArrayUtils.randomN([1, 2, 3, 4, 5], 3);
1411
-
1412
- // Zip and unzip
1413
- ArrayUtils.zip([1, 2, 3], ["a", "b", "c"]); // [[1, "a"], [2, "b"], [3, "c"]]
1414
-
1415
- // Set operations
1416
- ArrayUtils.difference([1, 2, 3, 4], [2, 4]); // [1, 3]
1417
- ArrayUtils.intersection([1, 2, 3], [2, 3, 4]); // [2, 3]
1418
- ArrayUtils.union([1, 2], [2, 3]); // [1, 2, 3]
1419
-
1420
- // Partition by predicate
1421
- const [evens, odds] = ArrayUtils.partition([1, 2, 3, 4, 5], (n) => n % 2 === 0);
1422
- // evens: [2, 4], odds: [1, 3, 5]
1423
-
1424
- // Math operations
1425
- ArrayUtils.sum([1, 2, 3, 4]); // 10
1426
- ArrayUtils.average([1, 2, 3, 4]); // 2.5
1427
- ArrayUtils.min([3, 1, 4, 1, 5]); // 1
1428
- ArrayUtils.max([3, 1, 4, 1, 5]); // 5
1429
-
1430
- // Range generation
1431
- ArrayUtils.range(1, 5); // [1, 2, 3, 4]
1432
- ArrayUtils.range(0, 10, 2); // [0, 2, 4, 6, 8]
1433
-
1434
- // Rotate and transpose
1435
- ArrayUtils.rotate([1, 2, 3, 4], 2); // [3, 4, 1, 2]
1436
- ArrayUtils.transpose([
1437
- [1, 2],
1438
- [3, 4],
1439
- ]); // [[1, 3], [2, 4]]
1440
- ```
1441
-
1442
- ### Error Boundary
1443
-
1444
- - **ErrorBoundary**: **EN** comprehensive error handling with automatic retry logic, error history tracking, and global error handlers. **ES** manejo completo de errores con reintentos automáticos, historial de errores y handlers globales.
1445
-
1446
- ```ts
1447
- import {
1448
- ErrorBoundary,
1449
- AppError,
1450
- AppValidationError,
1451
- NotFoundError,
1452
- TimeoutError,
1453
- RateLimitError,
1454
- } from "bytekit";
1455
-
1456
- // Create error boundary with custom config
1457
- const boundary = new ErrorBoundary({
1458
- maxRetries: 3,
1459
- retryDelay: 1000,
1460
- });
1461
-
1462
- // Handle errors with custom handlers
1463
- boundary.addHandler(async (error, context) => {
1464
- console.error(`Error in ${context.component}:`, error.message);
1465
- // Send to error tracking service
1466
- });
1467
-
1468
- // Execute async function with automatic retry
1469
- try {
1470
- const data = await boundary.execute(
1471
- async () => {
1472
- return await fetchData();
1473
- },
1474
- { component: "DataFetcher", userId: "user_123" }
1475
- );
1476
- } catch (error) {
1477
- if (error instanceof TimeoutError) {
1478
- console.log("Request timed out after retries");
1479
- }
1480
- }
1481
-
1482
- // Execute sync function with error handling
1483
- const result = boundary.executeSync(
1484
- () => {
1485
- return JSON.parse(jsonString);
1486
- },
1487
- { context: "json-parsing" }
1488
- );
1489
-
1490
- // Wrap functions for automatic error handling
1491
- const wrappedAsync = boundary.wrap(async (id: string) => {
1492
- return await api.get(`/users/${id}`);
1493
- });
1494
-
1495
- const wrappedSync = boundary.wrapSync((data: string) => {
1496
- return JSON.parse(data);
1497
- });
1498
-
1499
- // Get error history
1500
- const history = boundary.getErrorHistory(10);
1501
- history.forEach((entry) => {
1502
- console.log(`${entry.timestamp}: ${entry.error.message}`);
1503
- });
1504
-
1505
- // Create error report
1506
- const report = boundary.createErrorReport();
1507
- console.log(report);
1508
- // {
1509
- // timestamp: "2024-12-20T10:30:00.000Z",
1510
- // errors: [
1511
- // {
1512
- // code: "TIMEOUT",
1513
- // message: "Request timeout",
1514
- // statusCode: 408,
1515
- // timestamp: 1703068200000
1516
- // }
1517
- // ]
1518
- // }
1519
-
1520
- // Use global error boundary
1521
- import { getGlobalErrorBoundary } from "bytekit";
1522
-
1523
- const globalBoundary = getGlobalErrorBoundary({
1524
- maxRetries: 2,
1525
- retryDelay: 500,
1526
- });
1527
-
1528
- // Automatically catches unhandled rejections and global errors
1529
- globalBoundary.addHandler((error) => {
1530
- console.error("Unhandled error:", error);
1531
- });
1532
-
1533
- // Custom error types
1534
- try {
1535
- throw new AppValidationError("Invalid email format", {
1536
- component: "SignupForm",
1537
- });
1538
- } catch (error) {
1539
- if (error instanceof AppValidationError) {
1540
- console.log("Validation failed:", error.message);
1541
- }
1542
- }
1543
-
1544
- try {
1545
- throw new RateLimitError("Too many requests", 60, {
1546
- context: "api-call",
1547
- });
1548
- } catch (error) {
1549
- if (error instanceof RateLimitError) {
1550
- const retryAfter = error.context?.metadata?.retryAfter;
1551
- console.log(`Retry after ${retryAfter} seconds`);
1552
- }
1553
- }
1554
- ```
1555
-
1556
- ### Form Utilities
1557
-
1558
- - **FormUtils**: **EN** form validation and state management with built-in validators, async validation, and framework-agnostic design. **ES** validación de formularios y gestión de estado con validadores integrados, validación async y agnóstico del framework.
1559
-
1560
- ```ts
1561
- import { FormUtils, createForm, Validators } from "bytekit";
1562
-
1563
- // Create form with validation rules
1564
- const form = new FormUtils({
1565
- initialValues: {
1566
- email: "",
1567
- password: "",
1568
- confirmPassword: "",
1569
- },
1570
- rules: {
1571
- email: {
1572
- required: "Email is required",
1573
- email: "Invalid email format",
1574
- },
1575
- password: {
1576
- required: true,
1577
- minLength: 8,
1578
- custom: (value) => {
1579
- return /[A-Z]/.test(value)
1580
- ? true
1581
- : "Must contain uppercase letter";
1582
- },
1583
- },
1584
- confirmPassword: {
1585
- required: true,
1586
- custom: (value) => {
1587
- return Validators.match(value, form.getValue("password"))
1588
- ? true
1589
- : "Passwords do not match";
1590
- },
1591
- },
1592
- },
1593
- validateOnChange: true,
1594
- validateOnBlur: true,
1595
- onSubmit: async (values) => {
1596
- console.log("Form submitted:", values);
1597
- },
1598
- onError: (errors) => {
1599
- console.error("Validation errors:", errors);
1600
- },
1601
- });
1602
-
1603
- // Update field value
1604
- form.setValue("email", "user@example.com");
1605
-
1606
- // Get field state
1607
- const emailError = form.getFieldError("email");
1608
- const isTouched = form.isTouched("email");
1609
- const isDirty = form.isDirty("email");
1610
-
1611
- // Validate single field
1612
- await form.validateField("email");
1613
-
1614
- // Validate all fields
1615
- const errors = await form.validate();
1616
-
1617
- // Submit form
1618
- const success = await form.submit();
1619
-
1620
- // Get form state
1621
- const state = form.getState();
1622
- console.log(state);
1623
- // {
1624
- // values: { email: "...", password: "...", confirmPassword: "..." },
1625
- // errors: { email: "", password: "", confirmPassword: "" },
1626
- // touched: { email: true, password: true, confirmPassword: false },
1627
- // dirty: { email: true, password: true, confirmPassword: false },
1628
- // isValidating: false,
1629
- // isValid: true
1630
- // }
1631
-
1632
- // Create bindings for framework integration (React, Vue, etc.)
1633
- const emailBinding = form.createBinding("email");
1634
- // {
1635
- // value: "user@example.com",
1636
- // onChange: (value) => form.setValue("email", value),
1637
- // onBlur: () => form.touchField("email"),
1638
- // error: "",
1639
- // touched: true,
1640
- // dirty: true
1641
- // }
1642
-
1643
- // Reset form
1644
- form.reset();
1645
-
1646
- // Serialize/deserialize
1647
- const data = form.serialize();
1648
- form.deserialize({ email: "new@example.com" });
1649
-
1650
- // Built-in validators
1651
- Validators.required("value"); // true
1652
- Validators.email("test@example.com"); // true
1653
- Validators.minLength("password", 8); // true
1654
- Validators.maxLength("username", 20); // true
1655
- Validators.pattern("12345", /^\d+$/); // true
1656
- Validators.url("https://example.com"); // true
1657
- Validators.match("password", "password"); // true
1658
-
1659
- // Factory function
1660
- const signupForm = createForm({
1661
- initialValues: { username: "", email: "" },
1662
- rules: {
1663
- username: { required: true, minLength: 3 },
1664
- email: { required: true, email: true },
1665
- },
1666
- });
1667
- ```
1668
-
1669
- ```
1670
-
1671
- import {
1672
- createLogger,
1673
- withTiming,
1674
- createStopwatch,
1675
- StorageManager,
1676
- EnvManager,
1677
- } from "bytekit";
1678
-
1679
- const logger = createLogger({ namespace: "payments", level: "debug" });
1680
-
1681
- await withTiming("settlements", async () => {
1682
- const stopwatch = createStopwatch({ label: "batch-download", logger });
1683
- const batch = await downloadPayments();
1684
- stopwatch.log({ records: batch.length });
1685
- });
1686
-
1687
- const storage = new StorageManager();
1688
- storage.set("token", "abc123", 60_000);
1689
- const env = new EnvManager();
1690
- const apiKey = env.require("API_KEY");
1691
-
1692
- ```
1693
-
1694
- - `DateUtils`: **EN** safe parsing, add/subtract, configurable diffs, `isSameDay`. **ES** parseo seguro, sumas/restas, diferencias configurables e `isSameDay`.
1695
- - `StringUtils`: **EN** slugify, capitalize, masking, interpolation, query strings. **ES** slugify, capitalización, máscaras, interpolación, query strings.
1696
- - `Validator`: **EN** lightweight synchronous validators. **ES** validadores sincrónicos livianos.
1697
- - `StorageManager`: **EN** safe wrapper for `localStorage`/`sessionStorage`. **ES** adaptador seguro para storage del navegador.
1698
-
1699
- ## Toolkit Catalog / Catálogo de herramientas
1700
-
1701
- ### ApiClient
1702
-
1703
- - **EN**: Typed HTTP client with retries, localized errors, interceptors, and custom fetch support for Node/browsers.
1704
- **ES**: Cliente HTTP tipado con reintentos, errores localizados, interceptores y `fetch` personalizable para Node/navegadores.
1705
-
1706
- ```ts
1707
- import { ApiClient } from "bytekit";
1708
-
1709
- const api = new ApiClient({
1710
- baseUrl: "https://api.example.com",
1711
- defaultHeaders: { "X-Team": "development" },
1712
- });
1713
-
1714
- const user = await api.get("/users/1", {
1715
- searchParams: { locale: "es" },
1716
- });
1717
- ```
1718
-
1719
- ### createLogger
1720
-
1721
- - **EN**: Structured logger with levels, namespaces, transports for Node/browser, and child loggers.
1722
- **ES**: Logger estructurado con niveles, namespaces, transports para Node/browser y loggers hijos.
1723
-
1724
- ```ts
1725
- import { createLogger } from "bytekit";
1726
-
1727
- const logger = createLogger({ namespace: "payments", level: "info" });
1728
- logger.warn("payment delayed", { id: "tx_1" });
1729
-
1730
- const workerLogger = logger.child("worker");
1731
- workerLogger.debug("processing batch", { size: 20 });
1732
- ```
1733
-
1734
- ### Timing & Debug Utilities
1735
-
1736
- - **EN**: `createStopwatch`, `withTiming`, `measureAsync`, `captureDebug`, and `Profiler` help you capture execution times and emit logs automatically.
1737
- **ES**: `createStopwatch`, `withTiming`, `measureAsync`, `captureDebug` y `Profiler` facilitan medir tiempos y loguear automáticamente.
1738
-
1739
- ```ts
1740
- import { createStopwatch, withTiming, measureAsync, Profiler } from "bytekit";
1741
-
1742
- const stopwatch = createStopwatch({ label: "sync-users" });
1743
- // ... run task
1744
- stopwatch.log({ records: 42 });
1745
-
1746
- await withTiming("refresh-cache", async () => fetchCache());
1747
- const { result, durationMs } = await measureAsync("bill-run", () =>
1748
- processBills()
1749
- );
1750
-
1751
- const profiler = new Profiler();
1752
- profiler.start("db");
1753
- await queryDb();
1754
- profiler.end("db");
1755
- console.table(profiler.summary());
1756
- ```
1757
-
1758
- ### DateUtils
1759
-
1760
- - **parse / isValid**: **EN** accept `Date`, ISO strings, timestamps; return normalized Date or boolean. **ES** aceptan `Date`, string ISO o timestamp y devuelven Date normalizada o booleano.
1761
- - **toISODate**: **EN** format to `YYYY-MM-DD` without timezone surprises. **ES** formatea como `YYYY-MM-DD` evitando problemas de zona horaria.
1762
- - **startOfDay / endOfDay**: **EN** clamp hours to `00:00:00.000` or `23:59:59.999`. **ES** ajusta horas al inicio o final del día.
1763
- - **add**: **EN** add duration (`days`, `hours`, `minutes`, `seconds`, `milliseconds`). **ES** suma duraciones con granularidad configurable.
1764
- - **diff / diffInDays**: **EN** difference between two dates with unit + rounding + absolute options. **ES** diferencia entre fechas con unidad, redondeo y valor absoluto configurable.
1765
- - **isSameDay / isBefore / isAfter**: **EN** compare normalized dates. **ES** compara fechas normalizadas.
1766
- - **format**: **EN** locale-aware short date (`es-AR` default). **ES** formatea con `toLocaleDateString`.
1767
-
1768
- ```ts
1769
- DateUtils.isSameDay("2024-10-10", new Date());
1770
- DateUtils.diff(new Date("2024-01-01"), Date.now(), {
1771
- unit: "days",
1772
- rounding: "round",
1773
- absolute: true,
1774
- });
1775
- ```
1776
-
1777
- ### StringUtils
1778
-
1779
- - **removeDiacritics / compactWhitespace**: **EN** normalize text for comparisons or rendering. **ES** normalizan texto para comparaciones o UI.
1780
- - **slugify**: **EN** create URL-friendly IDs with configurable separator/lowercase. **ES** genera slugs configurables.
1781
- - **capitalize / capitalizeWords**: **EN/ES** capitaliza respetando locale.
1782
- - **truncate**: **EN** trims long strings with optional ellipsis + word boundaries. **ES** recorta textos largos respetando palabras.
1783
- - **mask**: **EN** hide sensitive parts with custom `maskChar`, `visibleStart`, `visibleEnd`. **ES** oculta secciones sensibles con máscara configurable.
1784
- - **interpolate**: **EN** replace `{{placeholders}}` with nested object values (strict/fallback/transform). **ES** interpolación con soporte para rutas y validación.
1785
- - **initials**: **EN** generate up to `limit` initials. **ES** genera iniciales rápido.
1786
- - **toQueryString**: **EN** serialize nested objects/arrays with formats (`repeat`, `bracket`, `comma`). **ES** serializa objetos y arrays a query strings.
1787
-
1788
- ```ts
1789
- StringUtils.mask("4242424242424242", { visibleStart: 4, visibleEnd: 2 });
1790
- StringUtils.toQueryString({
1791
- page: 1,
1792
- tags: ["lab", "team"],
1793
- filters: { status: "active" },
1794
- });
1795
- ```
1796
-
1797
- ### StorageManager
1798
-
1799
- - **StorageManager**: **EN** wraps any `Storage` (default `localStorage`) with safe JSON parsing and TTL support. **ES** envuelve cualquier `Storage` con parseo seguro y expiración opcional.
1800
- - **set/get/remove/clear**: **EN** persist typed values, remove expired entries automatically. **ES** guarda valores tipados y limpia expirados.
1801
-
1802
- ```ts
1803
- const storage = new StorageManager(sessionStorage);
1804
- storage.set("session", { token: "abc" }, 60_000);
1805
- const session = storage.get<{ token: string }>("session");
1806
- ```
1807
-
1808
- ### EnvManager
1809
-
1810
- - **get / require**: **EN** read ENV vars from Node (via `process.env`) or Vite-style browser builds (`import.meta.env`). **ES** lee env vars en Node o navegador y marca obligatorias con `require`.
1811
- - **isProd**: **EN** check `NODE_ENV`/`MODE`. **ES** detecta modo producción.
1812
-
1813
- ```ts
1814
- const env = new EnvManager();
1815
- const apiBase = env.require("API_BASE_URL");
1816
- if (env.isProd()) {
1817
- // toggle prod-only behavior
1818
- }
1819
- ```
1820
-
1821
- ### Validator
1822
-
1823
- - **Identity**: **EN** `isEmail`, `isUUIDv4`, `isDni`, `isCuit`, `isCbu`. **ES** validaciones de identidad y banking locales.
1824
- - **Phones**: **EN** `isInternationalPhone`, `isPhoneE164`, `isLocalPhone(locale)`. **ES** valida teléfonos internacionales y locales con patrones por país.
1825
- - **Security**: **EN** `isStrongPassword`, `isOneTimeCode`. **ES** contraseñas fuertes y códigos OTP.
1826
- - **General**: **EN** `isUrl`, `isEmpty`, length guards, regex matcher, `isDateRange`. **ES** helpers generales para formularios.
1827
-
1828
- ```ts
1829
- Validator.isStrongPassword("SecurePass!2024", { minLength: 10 });
1830
- Validator.isLocalPhone("11 5555-7777", "es-AR");
1831
- ```
1832
-
1833
- ### EventEmitter
1834
-
1835
- - **EN**: Pub/sub event system with sync/async listeners, once listeners, error handling, and listener tracking.
1836
- **ES**: Sistema de eventos pub/sub con listeners síncronos/asíncronos, listeners únicos, manejo de errores y seguimiento.
1837
-
1838
- ```ts
1839
- import { EventEmitter, createEventEmitter } from "bytekit";
1840
-
1841
- // Create event emitter with typed events
1842
- const emitter = new EventEmitter<{
1843
- "user:login": { userId: string; timestamp: number };
1844
- "user:logout": { userId: string };
1845
- error: Error;
1846
- }>();
1847
-
1848
- // Register listeners
1849
- emitter.on("user:login", async (data) => {
1850
- console.log(`User ${data.userId} logged in`);
1851
- await trackEvent(data);
1852
- });
1853
-
1854
- // One-time listener
1855
- emitter.once("user:logout", (data) => {
1856
- console.log(`User ${data.userId} logged out`);
1857
- });
1858
-
1859
- // Emit events
1860
- await emitter.emit("user:login", {
1861
- userId: "user_123",
1862
- timestamp: Date.now(),
1863
- });
1864
-
1865
- // Sync emit
1866
- emitter.emitSync("user:logout", { userId: "user_123" });
1867
-
1868
- // Error handling
1869
- emitter.onError((data, error) => {
1870
- console.error("Event error:", error);
1871
- });
1872
-
1873
- // Listener management
1874
- const count = emitter.listenerCount("user:login");
1875
- emitter.removeAllListeners("user:login");
1876
-
1877
- // Factory function
1878
- const events = createEventEmitter<{ message: string }>();
1879
- ```
1880
-
1881
- ### DiffUtils
1882
-
1883
- - **EN**: Deep object comparison, patch generation/application, and merge strategies for tracking changes.
1884
- **ES**: Comparación profunda de objetos, generación/aplicación de parches y estrategias de merge para rastrear cambios.
1885
-
1886
- ```ts
1887
- import { DiffUtils } from "bytekit";
1888
-
1889
- // Detect changes
1890
- const old = { name: "John", age: 30, email: "john@example.com" };
1891
- const new_ = { name: "Jane", age: 31, phone: "555-1234" };
1892
-
1893
- const diff = DiffUtils.diff(old, new_);
1894
- console.log(diff);
1895
- // {
1896
- // changed: ["name", "age"],
1897
- // added: ["phone"],
1898
- // removed: ["email"]
1899
- // }
1900
-
1901
- // Create patches (JSON Patch format)
1902
- const patches = DiffUtils.createPatch(old, new_);
1903
- console.log(patches);
1904
- // [
1905
- // { op: "replace", path: "name", value: "Jane" },
1906
- // { op: "replace", path: "age", value: 31 },
1907
- // { op: "add", path: "phone", value: "555-1234" },
1908
- // { op: "remove", path: "email" }
1909
- // ]
1910
-
1911
- // Apply patches
1912
- const result = DiffUtils.applyPatch(old, patches);
1913
- console.log(result); // { name: "Jane", age: 31, phone: "555-1234" }
1914
-
1915
- // Deep equality check
1916
- DiffUtils.deepEqual({ a: { b: 1 } }, { a: { b: 1 } }); // true
1917
- DiffUtils.deepEqual({ a: { b: 1 } }, { a: { b: 2 } }); // false
1918
- ```
1919
-
1920
- ### PollingHelper
1921
-
1922
- - **EN**: Intelligent polling with exponential backoff, stop conditions, and max attempts for async operations.
1923
- **ES**: Polling inteligente con backoff exponencial, condiciones de parada e intentos máximos para operaciones async.
1924
-
1925
- ```ts
1926
- import { PollingHelper, createPoller } from "bytekit";
1927
-
1928
- // Poll until condition is met
1929
- const poller = new PollingHelper(
1930
- async () => {
1931
- const status = await checkJobStatus();
1932
- return status === "completed";
1933
- },
1934
- {
1935
- interval: 1000, // Start with 1 second
1936
- maxAttempts: 30,
1937
- backoffMultiplier: 1.5, // Exponential backoff
1938
- stopCondition: (result) => result === true,
1939
- }
1940
- );
1941
-
1942
- const result = await poller.start();
1943
- console.log(result);
1944
- // {
1945
- // success: true,
1946
- // attempts: 5,
1947
- // lastResult: true,
1948
- // totalTimeMs: 3500
1949
- // }
1950
-
1951
- // Handle failure
1952
- if (!result.success) {
1953
- console.log(`Failed after ${result.attempts} attempts`);
1954
- }
1955
-
1956
- // Factory function
1957
- const filePoller = createPoller(
1958
- async () => {
1959
- return await fileExists("output.txt");
1960
- },
1961
- { interval: 500, maxAttempts: 60 }
1962
- );
1963
- ```
1964
-
1965
- ### CryptoUtils
1966
-
1967
- - **EN**: Token/UUID generation, base64 encoding, hashing, HMAC, and constant-time comparison for security.
1968
- **ES**: Generación de tokens/UUIDs, codificación base64, hashing, HMAC y comparación en tiempo constante para seguridad.
1969
-
1970
- ```ts
1971
- import { CryptoUtils } from "bytekit";
1972
-
1973
- // Generate secure tokens
1974
- const token = CryptoUtils.generateToken(32); // 64 hex chars
1975
- const uuid = CryptoUtils.generateUUID(); // v4 UUID
1976
-
1977
- // Base64 encoding
1978
- const encoded = CryptoUtils.base64Encode("Hello, World!");
1979
- const decoded = CryptoUtils.base64Decode(encoded);
1980
-
1981
- // URL-safe base64 (no +, /, =)
1982
- const urlSafe = CryptoUtils.base64UrlEncode("data+with/special=chars");
1983
- const restored = CryptoUtils.base64UrlDecode(urlSafe);
1984
-
1985
- // Hashing
1986
- const hash = await CryptoUtils.hash("password");
1987
- const isValid = await CryptoUtils.verifyHash("password", hash);
1988
-
1989
- // Constant-time comparison (prevents timing attacks)
1990
- const match = CryptoUtils.constantTimeCompare(token1, token2);
1991
-
1992
- // HMAC signing
1993
- const signature = await CryptoUtils.hmac("message", "secret");
1994
- ```
1995
-
1996
- ### PaginationHelper
1997
-
1998
- - **EN**: Offset-limit and cursor-based pagination with state tracking and navigation.
1999
- **ES**: Paginación offset-limit y basada en cursores con seguimiento de estado y navegación.
2000
-
2001
- ```ts
2002
- import { PaginationHelper, createPaginator } from "bytekit";
2003
-
2004
- const items = Array.from({ length: 100 }, (_, i) => ({ id: i + 1 }));
2005
-
2006
- // Offset-limit pagination
2007
- const paginator = new PaginationHelper(items, {
2008
- pageSize: 10,
2009
- mode: "offset",
2010
- });
2011
-
2012
- // Get current page
2013
- const page1 = paginator.getCurrentPage(); // First 10 items
2014
-
2015
- // Navigate
2016
- paginator.next();
2017
- const page2 = paginator.getCurrentPage(); // Items 11-20
2018
-
2019
- paginator.previous();
2020
- const backToPage1 = paginator.getCurrentPage();
2021
-
2022
- // Jump to specific page
2023
- paginator.goToPage(5);
2024
-
2025
- // Get state
2026
- const state = paginator.getState();
2027
- console.log(state);
2028
- // {
2029
- // currentPage: 5,
2030
- // pageSize: 10,
2031
- // total: 100,
2032
- // totalPages: 10,
2033
- // hasNextPage: true,
2034
- // hasPreviousPage: true,
2035
- // offset: 40,
2036
- // limit: 10
2037
- // }
2038
-
2039
- // Cursor-based pagination
2040
- const cursorPaginator = new PaginationHelper(items, {
2041
- pageSize: 10,
2042
- mode: "cursor",
2043
- cursorField: "id",
2044
- });
2045
-
2046
- // Factory function
2047
- const userPaginator = createPaginator(users, { pageSize: 20 });
2048
- ```
2049
-
2050
- ### CacheManager
2051
-
2052
- - **EN**: Multi-tier cache (memory + localStorage) with TTL, LRU eviction, and statistics for performance optimization.
2053
- **ES**: Cache multi-nivel (memoria + localStorage) con TTL, evicción LRU y estadísticas para optimización de rendimiento.
2054
-
2055
- ```ts
2056
- import { CacheManager, createCacheManager } from "bytekit";
2057
-
2058
- const cache = new CacheManager({
2059
- maxSize: 100, // Max entries
2060
- ttl: 5 * 60 * 1000, // 5 minutes default
2061
- useLocalStorage: true, // Enable persistent cache
2062
- });
2063
-
2064
- // Set and get
2065
- cache.set("user:123", { id: 123, name: "John" }, 60_000); // 1 minute TTL
2066
- const user = cache.get("user:123");
2067
-
2068
- // Get or compute
2069
- const data = await cache.getOrCompute(
2070
- "expensive:key",
2071
- async () => {
2072
- return await fetchExpensiveData();
2073
- },
2074
- 10 * 60 * 1000
2075
- ); // Cache for 10 minutes
2076
-
2077
- // Check if exists
2078
- if (cache.has("user:123")) {
2079
- console.log("User cached");
2080
- }
2081
-
2082
- // Remove and clear
2083
- cache.remove("user:123");
2084
- cache.clear();
2085
-
2086
- // Statistics
2087
- const stats = cache.getStats();
2088
- console.log(stats);
2089
- // {
2090
- // hits: 42,
2091
- // misses: 8,
2092
- // hitRate: 0.84,
2093
- // size: 15,
2094
- // maxSize: 100
2095
- // }
2096
-
2097
- // Invalidate by pattern
2098
- cache.invalidatePattern("user:*");
2099
-
2100
- // Factory function
2101
- const apiCache = createCacheManager({ maxSize: 50 });
2102
- ```
2103
-
2104
- ### CompressionUtils
2105
-
2106
- - **EN**: String compression, base64 encoding, JSON minification, and gzip/deflate support for data optimization.
2107
- **ES**: Compresión de strings, codificación base64, minificación JSON y soporte gzip/deflate para optimización de datos.
2108
-
2109
- ```ts
2110
- import { CompressionUtils } from "bytekit";
2111
-
2112
- // Compress and decompress
2113
- const original = "Hello World Hello World Hello World";
2114
- const compressed = CompressionUtils.compress(original);
2115
- const decompressed = CompressionUtils.decompress(compressed);
2116
-
2117
- // Base64 encoding
2118
- const encoded = CompressionUtils.base64Encode("data");
2119
- const decoded = CompressionUtils.base64Decode(encoded);
2120
-
2121
- // URL-safe base64
2122
- const urlSafe = CompressionUtils.base64UrlEncode("data+special/chars=");
2123
-
2124
- // JSON utilities
2125
- const json = '{ "name": "John", "age": 30 }';
2126
- const minified = CompressionUtils.minifyJSON(json);
2127
- const pretty = CompressionUtils.prettyJSON(minified, 2);
2128
-
2129
- // Compression ratio
2130
- const ratio = CompressionUtils.getCompressionRatio(original, compressed);
2131
- console.log(`Compression: ${ratio.toFixed(2)}%`);
2132
-
2133
- // Format bytes
2134
- CompressionUtils.formatBytes(1024); // "1 KB"
2135
- CompressionUtils.formatBytes(1024 * 1024); // "1 MB"
2136
-
2137
- // Serialize/deserialize with compression
2138
- const obj = { users: [{ id: 1, name: "John" }] };
2139
- const serialized = CompressionUtils.serializeCompressed(obj);
2140
- const restored = CompressionUtils.deserializeCompressed(serialized);
2141
-
2142
- // Gzip (Node.js)
2143
- const gzipped = await CompressionUtils.gzip(original);
2144
- const gunzipped = await CompressionUtils.gunzip(gzipped);
2145
-
2146
- // Deflate (Node.js)
2147
- const deflated = await CompressionUtils.deflate(original);
2148
- const inflated = await CompressionUtils.inflate(deflated);
2149
- ```
2150
-
2151
- ## Compatibility / Compatibilidad
2152
-
2153
- - Node.js >= 18 (ESM, `fetch`, `AbortController`, `URL`).
2154
- - Modern browsers (ships optional `cross-fetch` polyfill).
2155
-
2156
- ## CLI scaffolding / Generador CLI
2157
-
2158
- **EN:** Install the package globally or invoke it with `npx`. The `sutils` binary provides two powerful commands: scaffolding resource folders with CRUD helpers and generating TypeScript types from API responses.
2159
- **ES:** Instalá el paquete globalmente o usalo con `npx`. El binario `sutils` proporciona dos comandos poderosos: crear carpetas de recursos con helpers CRUD y generar tipos TypeScript desde respuestas de API.
2160
-
2161
- ### Create Command / Comando Create
2162
-
2163
- ```bash
2164
- npx sutils create users
2165
- ```
2166
-
2167
- **What is generated / Qué se genera:**
2168
-
2169
- - `api/<resource>/index.ts`: typed CRUD helpers built on `bytekit`' `ApiClient`, including shape placeholders, filter helpers, and `list/get/create/update/delete` functions.
2170
- - `hooks/<resource>/use<ResourcePlural>.ts`: Query library hooks (React Query or RTK Query, configurable via `--queryLib`) that invalidate the corresponding queries and wire mutations.
2171
- - `hooks/<resource>/index.ts`: re-exports the generated hooks.
2172
-
2173
- The generator accepts `--apiDir`, `--hooksDir`, `--route`, `--queryLib`, and `--force`; directories default to `api`/`hooks`, the route defaults to the resource name, `--queryLib` defaults to `react-query`, and `--force` overwrites existing files. It also respects nested resource paths like `admin/users`.
2174
-
2175
- **Query Library Options / Opciones de Librería de Queries:**
2176
-
2177
- - `--queryLib=react-query` (default): Generates hooks using `@tanstack/react-query` (React Query).
2178
- - `--queryLib=rtk-query`: Generates API slice using `@reduxjs/toolkit/query/react` (RTK Query).
2179
-
2180
- **Examples / Ejemplos:**
2181
-
2182
- ```bash
2183
- # Create with React Query (default)
2184
- npx sutils create users
2185
-
2186
- # Create with RTK Query
2187
- npx sutils create users --queryLib=rtk-query
2188
-
2189
- # Create with custom directories and RTK Query
2190
- npx sutils create payments --apiDir=services --hooksDir=app/hooks --route=/billing/payments --queryLib=rtk-query --force
2191
- ```
2192
-
2193
- **React Query Setup / Configuración de React Query:**
2194
-
2195
- React Query must be available in the consuming project:
2196
-
2197
- ```bash
2198
- npm install @tanstack/react-query
2199
- ```
2200
-
2201
- The generated hooks expect an `ApiClient` instance that you pass as the first argument:
2202
-
2203
- ```ts
2204
- import { useUsers } from "./hooks/users";
2205
- import { apiClient } from "./api/client";
2206
-
2207
- export function UsersList() {
2208
- const { data, isLoading } = useUsers(apiClient);
2209
- // ...
2210
- }
2211
- ```
2212
-
2213
- **RTK Query Setup / Configuración de RTK Query:**
2214
-
2215
- RTK Query must be available in the consuming project:
2216
-
2217
- ```bash
2218
- npm install @reduxjs/toolkit react-redux
2219
- ```
2220
-
2221
- The generated API slice should be added to your Redux store:
2222
-
2223
- ```ts
2224
- import { configureStore } from "@reduxjs/toolkit";
2225
- import { userApi } from "./hooks/users";
2226
-
2227
- export const store = configureStore({
2228
- reducer: {
2229
- [userApi.reducerPath]: userApi.reducer,
2230
- },
2231
- middleware: (getDefaultMiddleware) =>
2232
- getDefaultMiddleware().concat(userApi.middleware),
2233
- });
2234
- ```
2235
-
2236
- Then use the generated hooks in your components:
2237
-
2238
- ```ts
2239
- import { useListUsersQuery, useCreateUserMutation } from "./hooks/users";
2240
-
2241
- export function UsersList() {
2242
- const { data, isLoading } = useListUsersQuery();
2243
- const [createUser] = useCreateUserMutation();
2244
- // ...
2245
- }
2246
- ```
2247
-
2248
- ### Types Command / Comando Types
2249
-
2250
- **EN:** Generate TypeScript type definitions automatically from API responses. Perfect for quickly creating types without manual work.
2251
- **ES:** Genera definiciones de tipos TypeScript automáticamente desde respuestas de API. Perfecto para crear tipos rápidamente sin trabajo manual.
2252
-
2253
- ```bash
2254
- # Generate types from GET endpoint
2255
- npx sutils types https://api.example.com/users
2256
-
2257
- # Generate types with custom output and name
2258
- npx sutils types https://api.example.com/users --output=user-types.ts --name=User
2259
-
2260
- # Generate types from POST endpoint with custom headers
2261
- npx sutils types https://api.example.com/users --method=POST --header=Authorization:Bearer\ token
2262
- ```
2263
-
2264
- **Options / Opciones:**
2265
-
2266
- - `--method=<METHOD>`: HTTP method (default: GET). Supports GET, POST, PUT, PATCH, DELETE.
2267
- - `--output=<file>`: Output file path (default: types.ts).
2268
- - `--name=<name>`: Type name (default: ApiResponse).
2269
- - `--header=<key:value>`: Custom header (can be used multiple times).
2270
-
2271
- **Example output / Ejemplo de salida:**
2272
-
2273
- ```ts
2274
- // Auto-generated types from API response
2275
- // Generated at 2024-12-20T10:30:00.000Z
2276
-
2277
- export interface ApiResponse {
2278
- id: string;
2279
- name: string;
2280
- email: string;
2281
- createdAt: string;
2282
- updatedAt: string;
2283
- }
2284
- ```
2285
-
2286
- ## TypeScript Compatibility / Compatibilidad con TypeScript
2287
-
2288
- **EN:** The package is tested and verified to work with multiple TypeScript versions.
2289
- **ES:** El paquete está testeado y verificado para funcionar con múltiples versiones de TypeScript.
2290
-
2291
- ### Supported Versions / Versiones Soportadas
2292
-
2293
- | Version | Status | Notes |
2294
- | ------- | ------------------- | --------------------------------------------- |
2295
- | 5.9.3+ | ✅ **Recommended** | Full ES2023 support, modern module resolution |
2296
- | 6.0.0+ | ✅ **Future-proof** | Compatible with upcoming TypeScript versions |
2297
- | 5.6.3 | ⚠️ Partial | Requires ES2022 target instead of ES2023 |
2298
- | < 5.6 | ❌ Not supported | Missing ES2023 features and modern tooling |
2299
-
2300
- ### Recommended Configuration / Configuración Recomendada
2301
-
2302
- **EN:** Use TypeScript 5.9.3 or later for optimal compatibility and zero deprecation warnings.
2303
- **ES:** Usá TypeScript 5.9.3 o posterior para compatibilidad óptima y sin warnings de deprecación.
2304
-
2305
- ```bash
2306
- npm install --save-dev typescript@^5.9.3
2307
- ```
2308
-
2309
- ### ES2023 Features Used / Características ES2023 Utilizadas
2310
-
2311
- The package leverages these ES2023 features:
2312
-
2313
- - `Array.prototype.findLast()` - Find last element matching predicate
2314
- - `Array.prototype.findLastIndex()` - Find last index matching predicate
2315
- - `Array.prototype.at()` - Access array elements with negative indices
2316
- - `String.prototype.at()` - Access string characters with negative indices
2317
- - `Object.hasOwn()` - Check object property ownership
2318
- - Experimental Decorators
2319
-
2320
- ### Migration from Older Versions / Migración desde Versiones Antiguas
2321
-
2322
- **From TypeScript 5.6 to 5.9:**
2323
-
2324
- ```bash
2325
- # 1. Update TypeScript
2326
- npm install --save-dev typescript@^5.9.3
2327
-
2328
- # 2. Update tsconfig.json
2329
- # Change target from ES2022 to ES2023
2330
- # Change moduleResolution from node to bundler
2331
-
2332
- # 3. No code changes needed
2333
- npm run build
2334
- ```
2335
-
2336
- **From TypeScript 5.9 to 6.0+:**
2337
-
2338
- ```bash
2339
- # 1. Update TypeScript
2340
- npm install --save-dev typescript@^6.0.0
2341
-
2342
- # 2. No tsconfig changes needed (already future-proof)
2343
-
2344
- # 3. No code changes needed
2345
- npm run build
2346
- ```
2347
-
2348
- ### Testing TypeScript Compatibility / Testeando Compatibilidad
2349
-
2350
- **EN:** Run the test suite to verify TypeScript compatibility:
2351
- **ES:** Ejecutá la suite de tests para verificar compatibilidad con TypeScript:
2352
-
2353
- ```bash
2354
- npm run test
2355
- ```
2356
-
2357
- ## Migration from @sebamar88/utils / Migración desde @sebamar88/utils
2358
-
2359
- **EN:** If you were using `@sebamar88/utils`, simply update your package name to `bytekit`. No code changes are required—all APIs remain the same.
2360
-
2361
- **ES:** Si estabas usando `@sebamar88/utils`, simplemente actualiza el nombre del paquete a `bytekit`. No se requieren cambios de código—todas las APIs permanecen igual.
2362
-
2363
- ### Before / Antes
2364
-
2365
- ```bash
2366
- npm install @sebamar88/utils
2367
- ```
2368
-
2369
- ```typescript
2370
- import { ApiClient, DateUtils } from "@sebamar88/utils";
2371
- ```
2372
-
2373
- ### After / Después
2374
-
2375
- ```bash
2376
- npm install bytekit
2377
- ```
2378
-
2379
- ```typescript
2380
- import { ApiClient, DateUtils } from "bytekit";
2381
- ```
2382
-
2383
- ### Version History / Historial de Versiones
2384
-
2385
- - **v0.1.10+** - `bytekit` (current)
2386
- - **v0.1.9 and earlier** - `@sebamar88/utils` (deprecated)
2387
-
2388
- **EN:** The package was renamed from `@sebamar88/utils` to `bytekit` starting with v0.1.10. All functionality remains the same.
2389
-
2390
- **ES:** El paquete fue renombrado de `@sebamar88/utils` a `bytekit` a partir de v0.1.10. Toda la funcionalidad permanece igual.
2391
-
2392
- ## License / Licencia
213
+ ---
2393
214
 
2394
- MIT © 2024 Sebastián Martinez
215
+ **💡 Need help?** Check the **[Wiki](https://github.com/sebamar88/bytekit/wiki)** or **[open an issue](https://github.com/sebamar88/bytekit/issues)**.