@dxtmisha/functional-basic 1.6.4 → 1.8.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/CHANGELOG.md CHANGED
@@ -2,6 +2,28 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [1.8.0] - 2026-07-25
6
+
7
+ ### Added
8
+ - **domContentLoaded**: Introduced `domContentLoaded` DOM helper function to safely execute callbacks once the DOM is loaded, with comprehensive unit tests (`domContentLoaded.test.ts`).
9
+ - **toNumberPositive**: Introduced `toNumberPositive` utility function to convert inputs to positive finite numbers (`> 0`) or return a default fallback (`0`), with unit tests (`toNumberPositive.test.ts`).
10
+ - **sortList**: Introduced `sortList` standalone utility function for multi-column array sorting by property paths, directions (`'asc'`, `'desc'`), or custom comparison functions using locale-aware `Intl.Collator`.
11
+ - **sortTypes**: Added `SortDir`, `SortColumnItem`, and `SortFunction` type definitions, extending `SortColumnItem` to allow optional `dir` and `column` properties for 3-state sorting cycles (`asc` -> `desc` -> `undefined`).
12
+ - **getRandomItem**: Introduced a new `getRandomItem` utility function to safely retrieve a random element from arrays, objects, or primitive values, returning `undefined` when empty or missing, with full bilingual JSDocs.
13
+ - **Tests**: Added unit test suites for `sortList` (`sortList.test.ts`), `getRandomItem` (`getRandomItem.test.ts`), `domContentLoaded` (`domContentLoaded.test.ts`), and `toNumberPositive` (`toNumberPositive.test.ts`).
14
+
15
+ ## [1.7.1] - 2026-07-14
16
+
17
+ ### Changed
18
+ - **ApiInstance**: Refactored URL generation to use a protected `geo` (`GeoInstance`) field initialized via `Geo.getObject()`, calling instance-level methods instead of static `Geo` class methods.
19
+ - **ServerStorage**: Added an optional `storageList` parameter to `set()` and forwarded the resolved storage block from `get()` to prevent resolving the storage context multiple times.
20
+
21
+ ## [1.7.0] - 2026-07-11
22
+
23
+ ### Added
24
+ - **getLast**: Introduced a new `getLast` utility function to safely retrieve the last element from arrays or objects, with full bilingual JSDocs.
25
+ - **Tests**: Created a comprehensive unit test suite (`getLast.test.ts`) to validate last-element extraction across multiple data types.
26
+
5
27
  ## [1.6.2] - 2026-07-06
6
28
 
7
29
  ### Changed
package/README.md CHANGED
@@ -81,3 +81,5 @@ Full API reference, examples, and guides:
81
81
  ## License
82
82
 
83
83
  [MIT](LICENSE)
84
+
85
+
package/ai-description.md CHANGED
@@ -1,19 +1,7 @@
1
- ### Core Purpose
2
- The library provides an isomorphic utility framework for managing high-level application concerns in JavaScript/TypeScript environments (SSR and DOM). It includes robust abstractions for API communication (REST/Fetch), structured state management, DOM-safe event handling, internationalization, and reactive data storage.
1
+ An isomorphic TypeScript utility framework designed to provide core runtime services for web applications across browser and Server-Side Rendering (SSR) environments. Its primary functions include wrapping the Fetch API with request/response caching and hydration, state management isolated by request context, comprehensive internationalization (i18n, unit conversions, phone masking, date/number formatting), SEO meta tag synchronization, reactive URL hash and query parameter tracking, managed DOM event lifecycle handling, in-memory list search with string highlighting, and centralized error handling.
3
2
 
4
- ### Key Expositions
5
- * **API & Networking**: `Api` (singleton interface), `ApiInstance` (core requester), `ApiCache` (request memoization), `ApiError` (centralized error handling), `ApiHydration` (SSR data serialization), and `ApiHeaders`.
6
- * **State & Storage**: `DataStorage` (persistent storage with prefixes/expiration), `ServerStorage` (SSR-safe context isolation), `CookieStorage` (isomorphic cookie management), `Query`/`Hash` (URL-state management), and `Global` (app-wide data).
7
- * **UI & Events**: `EventItem` (DOM-safe, optimized event management with `ResizeObserver` and `scroll-sync`), `LoadingInstance` (global loading state), and `ScrollbarWidth` (layout utility).
8
- * **Localization & Formatting**: `Geo` (locale/timezone management), `GeoIntl` (Intl API wrapper), `GeoUnit` (metric/imperial conversion), `Translate` (i18n), and `Formatters` (currency, number, date, and pluralization utility).
9
- * **Utilities & Data**: `Formatters`, `SearchList` (search matching/caching), `ResumableTimer`, and a suite of functional utilities for object cloning, string/date manipulation, and DOM operations.
3
+ Api and ApiInstance manage Fetch-based HTTP communication featuring retries, custom headers, preparation hooks, and mock response emulation. ApiCache handles client and server data caching. ServerStorage and DataStorage provide isomorphic request-isolated state retention and browser storage abstraction with SSR hydration support. CookieStorage and Cookie manage client/server cookies consistently. Geo, GeoIntl, GeoPhone, GeoUnit, and Datetime form a localization engine handling Intl formatting, country phone masking, unit conversions, and date calculations. Translate and TranslateInstance manage synchronous and asynchronous translation batching. Query, QueryInstance, Hash, and HashInstance offer reactive, watchable interfaces for URL query strings and hash parameters. EventItem wraps DOM event listeners with ResizeObserver and requestAnimationFrame scroll optimizations. SearchList provides in-memory text search, regex generation, and matching string highlights. Meta, MetaOg, and MetaTwitter manage standard HTML, Open Graph, and Twitter Card metadata tags in the DOM or as HTML strings. ErrorCenter provides centralized error tracking and routing.
10
4
 
11
- ### Triggers for Studying ai-types.md
12
- Review `ai-types.md` whenever the following requirements arise:
13
- 1. **API Integration**: You need to implement new request methods, custom error handling for specific HTTP status codes, or configure global API middleware (`wrapper`/`preparation`).
14
- 2. **I18n/Formatting**: You are dealing with complex localization rules, unit conversions (Geo/Units), or pluralization requirements.
15
- 3. **SSR Consistency**: You are implementing features that must function identically on both the server and client (Hydration, `ServerStorage`, or `Datetime` formatting).
16
- 4. **Complex State**: You need to map or query data structures in memory using `SearchList` or utilize `BroadcastChannel` for cross-context messaging.
5
+ Studying ai-types.md is mandatory when implementing or typing API configurations (ApiFetch, ApiConfig, ApiHydrationItem), setting up application error handling (ErrorCenterCauseItem, ErrorCenterHandlerList), configuring complex list transformations (FormattersOptionsList, FormattersType), managing geographic and phone mask parameters (GeoItem, GeoDate, GeoPhoneValue), defining search parameters (SearchOptions, SearchColumns), configuring SEO meta types (MetaOpenGraphTag, MetaTwitterCard), or working with core generic utility types (ArrayToItem, NormalOrPromise, ObjectOrArray, NumberOrString).
17
6
 
18
- ### Integration Context
19
- The library acts as a foundational service layer between the application logic and the runtime environment. It is designed to be framework-agnostic but is particularly optimized for SSR-heavy environments (like Vue/React) where hydration of state (via `ServerStorage`) and safe access to global browser objects (via `isDomRuntime`) are critical. It wraps native `fetch`, `localStorage`, `sessionStorage`, `BroadcastChannel`, and `Intl` APIs into structured, type-safe, and singleton-accessible services.
7
+ The library operates as a foundational layer directly above native browser and Node.js runtime APIs (Fetch API, Intl API, DOM Window/Element interfaces, ResizeObserver, BroadcastChannel, Web Storage). It integrates with frontend SSR frameworks (such as Vue, React, Nuxt, or Next.js) by decoupling server-side request state via ServerStorage and generating safe client hydration scripts (getElementSafeScript) to prevent client-server hydration mismatches.
package/ai-doc.md CHANGED
@@ -2,140 +2,61 @@
2
2
 
3
3
  Framework-agnostic utility library. **Vue developers MUST search `@dxtmisha/functional` first**; use this ONLY if no reactive/Vue-specific analog exists.
4
4
 
5
- ---
5
+ ## 1. Coding Standards & Conventions
6
+ - **Class Structure**: Properties/Variables (`public`->`protected`->`private`) -> Constructor -> Public Methods (Getters -> Setters -> Core actions) -> Protected Methods -> Private Methods.
7
+ - **Style/Types**: `PascalCase` classes, `camelCase` methods/props, `UPPER_SNAKE_CASE` constants. No `any` (use `unknown`/generics). Explicit return types for ALL methods. Export all interfaces. Type files: `*Types.ts`. Use `@effect/schema` for schemas.
8
+ - **SSR Safety**: Isomorphic code. Do NOT store request state in globals. Use `isDomRuntime()` before `window`/`document`. Use `ServerStorage.get('key', () => new Class())` for request-isolated singletons.
6
9
 
7
- ## Coding Standards & Class Structure
10
+ ## 2. API Reference & Examples
8
11
 
9
- ### 1. Class Member Order
10
- 1. **Properties/Variables**: Top of class, ordered by visibility (`public` -> `protected` -> `private`). Initialize inline if possible.
11
- 2. **Constructor**: Follows properties. Parameter properties (e.g. `protected url: string`) allowed.
12
- 3. **Public Methods**:
13
- 1. Getters, checkers, status methods (`is*`, `get*`).
14
- 2. Setters & configuration (`set*`).
15
- 3. Core executors & actions (`request()`, `fetch()`, `show()`).
16
- 4. **Protected Methods**: Internal helpers for subclasses.
17
- 5. **Private Methods**: Internal helper logic at the very bottom.
18
-
19
- ### 2. Style & Type Conventions
20
- - **Naming**: Classes = `PascalCase`, Methods/Properties = `camelCase`, Constants = `UPPER_SNAKE_CASE`.
21
- - **TypeScript**: No `any` (use `unknown`/generics). Explicit return types on ALL methods (including `void`). Export all types/interfaces. Suffix type files with `Types` (e.g., `*Types.ts`). Use `@effect/schema` for API schemas if present.
22
- - **SSR Safety**: Isomorphic code. Do not store request-specific state in static/global variables. Use `isDomRuntime()` before accessing `window`/`document`/`location`. Use `ServerStorage.get(key, () => new Instance())` for request-isolated singletons.
23
-
24
- ---
25
-
26
- ## API Reference & Examples
27
-
28
- ### 1. HTTP Client (`Api`, `ApiInstance`, `ApiCache`)
12
+ ### HTTP Client & Caching
29
13
  ```typescript
30
14
  import { Api, ApiCache } from '@dxtmisha/functional-basic';
31
-
32
- // Config
33
- Api.setOrigin('https://api.example.com');
34
- Api.setUrl('/api/v1');
35
- Api.setRequestDefault({ client: 'web' });
15
+ Api.setOrigin('https://api.example.com'); Api.setUrl('/api/v1'); Api.setRequestDefault({ client: 'web' });
36
16
  Api.setHeaders(() => ({ Authorization: `Bearer ${localStorage.getItem('token') || ''}` }));
37
-
38
- // Interceptors
39
- Api.setPreparation(async (fetchOpts) => { if (fetchOpts.auth) fetchOpts.headers['X-Auth'] = '1'; });
40
- Api.setEnd(async (res, fetchOpts) => res.status === 401 ? { reset: true } : {});
41
-
42
- // Requests
43
- const users = await Api.request<User[]>('users'); // default GET
44
- const profile = await Api.get<User>({ path: 'profile' });
17
+ Api.setPreparation(async (opts) => { if (opts.auth) opts.headers['X-Auth'] = '1'; });
18
+ Api.setEnd(async (res) => res.status === 401 ? { reset: true } : {});
19
+ const users = await Api.request<User[]>('users'); // GET
45
20
  const updated = await Api.post<User>({ path: 'profile', request: { name: 'New' } });
46
-
47
- // Cache
48
- await ApiCache.set('key', { data: 1 }, 60000); // ms age
49
- const cached = await ApiCache.get<{ data: number }>('key');
21
+ await ApiCache.set('k', { a: 1 }, 60000); const cache = await ApiCache.get<{a: number}>('k');
50
22
  ```
51
23
 
52
- ### 2. State & Storage Management
24
+ ### Storage & State
53
25
  ```typescript
54
26
  import { DataStorage, CookieStorage, Cookie, ServerStorage } from '@dxtmisha/functional-basic';
55
-
56
- // DataStorage (localStorage/sessionStorage)
57
- DataStorage.setPrefix('my_app_');
58
- const userStorage = new DataStorage<{ id: string }>('user_session', false); // true for sessionStorage
59
- userStorage.set({ id: '123' });
60
- const user = userStorage.get({ id: 'guest' }); // fallback default
61
- userStorage.remove();
62
-
63
- // Cookies
64
- CookieStorage.set('theme', 'dark', { age: 31536000, secure: true, sameSite: 'lax' });
65
- const theme = CookieStorage.get<string>('theme', 'light');
66
- CookieStorage.remove('theme');
67
-
68
- const tokenCookie = new Cookie<string>('auth_token');
69
- tokenCookie.set('xyz123', { secure: true });
70
- const token = tokenCookie.get();
71
-
72
- // SSR Request-Isolated Storage
73
- const myService = ServerStorage.get('myService', () => new MyService());
27
+ DataStorage.setPrefix('app_');
28
+ const ls = new DataStorage<{ id: string }>('user', false); ls.set({ id: '1' }); ls.get({ id: '0' }); ls.remove();
29
+ CookieStorage.set('t', 'dark', { age: 31536000, secure: true }); CookieStorage.get<string>('t', 'light');
30
+ const c = new Cookie<string>('auth'); c.set('xyz', { secure: true }); c.get();
31
+ const srv = ServerStorage.get('svc', () => new Svc()); // SSR isolated
74
32
  ```
75
33
 
76
- ### 3. Geolocation & Localization
34
+ ### Geolocation, Formatting & Localization
77
35
  ```typescript
78
36
  import { Geo, GeoIntl, GeoFlag, GeoPhone } from '@dxtmisha/functional-basic';
79
-
80
- // Geo state
81
- const country = Geo.getCountry(); // e.g., 'VN'
82
- const lang = Geo.getLanguage(); // e.g., 'vi'
83
- Geo.set('en-US');
84
-
85
- // Formatters (Intl)
37
+ const country = Geo.getCountry(); const lang = Geo.getLanguage(); Geo.set('en-US');
86
38
  const intl = new GeoIntl('en-US');
87
- intl.number(123456.78); // '123,456.78'
88
- intl.currency(99.99, 'USD'); // '$99.99'
89
- intl.sizeFile(1024 * 1024 * 5); // '5.00 MB'
90
- intl.date(new Date(), 'date'); // 'Jun 18, 2026'
91
- intl.date(new Date(), 'time'); // '10:48 PM'
92
- intl.relative(new Date(Date.now() - 3600000)); // '1 hour ago'
93
- intl.plural(3, 'apple|apples'); // '3 apples' ('one|other' or 'one|few|many|other')
94
-
95
- // Flags & Phones
39
+ intl.number(1234.5); intl.currency(99, 'USD'); intl.sizeFile(1024*1024); intl.date(new Date(), 'date');
40
+ intl.relative(new Date(Date.now() - 3600000)); intl.plural(3, 'apple|apples');
96
41
  const flag = new GeoFlag().getFlag('VN');
97
- const phoneInfo = GeoPhone.getByPhone('+84900000000'); // .phone = cleaned string
98
- const mask = GeoPhone.toMask('84900000000');
42
+ const phone = GeoPhone.getByPhone('+84900000000'); const mask = GeoPhone.toMask('84900000000');
99
43
  ```
100
44
 
101
- ### 4. DOM, Safe Events & Helpers
45
+ ### DOM, Events & Helpers
102
46
  ```typescript
103
- import { EventItem, goScrollSmooth, writeClipboardData, getClipboardData } from '@dxtmisha/functional-basic';
47
+ import { EventItem, goScrollSmooth, writeClipboardData, getClipboardData, SearchList, Formatters, FormattersType, isFilled, isDomRuntime, copyObject, anyToString, sleep } from '@dxtmisha/functional-basic';
104
48
 
105
- // Leak-proof Event management
106
- const clickListener = new EventItem(window, 'click', (e) => console.log(e), { passive: true });
107
- clickListener.start();
108
- clickListener.stop(); // Call on destroy/cleanup!
49
+ // Safe Events (leak-proof)
50
+ const listener = new EventItem(window, 'click', console.log, { passive: true }); listener.start(); listener.stop();
109
51
 
110
52
  // DOM / Clipboard
111
- goScrollSmooth(document.getElementById('target'));
112
- await writeClipboardData('text');
113
- const text = await getClipboardData();
114
- ```
53
+ goScrollSmooth(document.getElementById('t')); await writeClipboardData('txt'); await getClipboardData();
115
54
 
116
- ### 5. Search & Formatting Utilities
117
- ```typescript
118
- import { SearchList, Formatters, FormattersType } from '@dxtmisha/functional-basic';
119
-
120
- // Search List with highlights
121
- const searcher = new SearchList([{ name: 'John Doe' }], ['name'], 'john');
122
- const results = searcher.to(); // returns matching items with highlighted markup in matching keys
123
-
124
- // Object Formatter
125
- const formatter = new Formatters({
126
- price: { type: FormattersType.currency, options: 'USD' },
127
- date: { type: FormattersType.date, options: { month: 'long', year: 'numeric' } }
128
- }, { price: 12000, date: '2026-06-18' });
129
- const formatted = formatter.to(); // { price: '$12,000.00', date: 'June 2026' }
130
- ```
131
-
132
- ### 6. General Helpers
133
- ```typescript
134
- import { isFilled, isDomRuntime, copyObject, anyToString, sleep } from '@dxtmisha/functional-basic';
55
+ // Search & Formatters
56
+ const res = new SearchList([{ n: 'John' }], ['n'], 'jo').to(); // Highlights matches
57
+ const fmt = new Formatters({ p: { type: FormattersType.currency, options: 'USD' } }, { p: 12 }).to();
135
58
 
136
- isFilled([]); // false (works for strings, arrays, objects, numbers, booleans)
137
- isDomRuntime(); // true if in browser
138
- const cloned = copyObject({ a: 1 });
139
- const str = anyToString(123);
140
- await sleep(500);
59
+ // General
60
+ isFilled([]); // false (strings, arrays, objects, numbers, booleans)
61
+ isDomRuntime(); const cloned = copyObject({ a: 1 }); const str = anyToString(123); await sleep(500);
141
62
  ```