@ylsoo/core 2.0.0 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,18 +1,18 @@
1
1
  <div align="center">
2
- <h1>@ylsoo/core (v2.0 Enterprise)</h1>
3
- <p><b>The official, enterprise-grade SDK powering advanced Ylsoo web and server products.</b></p>
2
+ <h1>@ylsoo/core (v2.2 Enterprise)</h1>
3
+ <p><b>The absolute standard in enterprise SDK architecture.</b></p>
4
4
 
5
5
  [![npm version](https://img.shields.io/npm/v/@ylsoo/core.svg?style=flat-square)](https://www.npmjs.com/package/@ylsoo/core)
6
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg?style=flat-square)](https://opensource.org/licenses/MIT)
7
7
  [![TypeScript Ready](https://img.shields.io/badge/TypeScript-Ready-blue?style=flat-square&logo=typescript)](https://www.typescriptlang.org/)
8
- [![Cross-Platform](https://img.shields.io/badge/Cross--Platform-Node.js%20%7C%20Browser-brightgreen?style=flat-square)](#)
8
+ [![Zero Defaults](https://img.shields.io/badge/Dependencies-0-brightgreen?style=flat-square)](#)
9
9
  </div>
10
10
 
11
11
  <hr>
12
12
 
13
13
  ## 🚀 Overview
14
14
 
15
- `@ylsoo/core` v2 has been completely rewritten into a powerful, modular architecture. It provides blazing-fast utility functions designed specifically for Ylsoo services. It runs identically on **modern browsers** and **Node.js** servers thanks to custom polyfills acting entirely natively, without a single external dependency!
15
+ `@ylsoo/core` v2.2 introduces tier-1 routing capabilities and highly rigorous A/B target evaluation. Everything operates entirely on native standard technologies, avoiding the devastating payload bloat of common frameworks.
16
16
 
17
17
  ## 📦 Installation
18
18
 
@@ -20,74 +20,72 @@
20
20
  npm i @ylsoo/core
21
21
  ```
22
22
 
23
- ## 🛠️ API Reference
23
+ ## 🛠️ V2.2 Enterprise Architecture Models
24
24
 
25
- ### 1. 🔐 Distributed Security (`ylsoo.crypto`)
26
- Leverages Web Crypto API natively to perform secure operations identically across browsers and servers.
27
- ```javascript
28
- const ylsoo = require('@ylsoo/core');
29
-
30
- // 1. Generate Secure V4 UUIDs
31
- const sessionID = ylsoo.crypto.uuid();
32
-
33
- // 2. Hash strings natively
34
- const secretHash = await ylsoo.crypto.hash('my_super_secret');
25
+ ### 1. 🛣️ Professional DOM Router (`ylsoo.router`)
26
+ An incredibly capable HTML5 Frontend matcher mimicking heavily advanced Vue/React dynamics.
35
27
 
36
- // 3. Encode/Decode Base64
37
- const encoded = ylsoo.crypto.encodeBase64('user:pass');
38
- ```
28
+ - **Dynamic Constraints**: Extracts `/:id/` params cleanly into variables.
29
+ - **Middleware Control**: Provides `beforeEach()` to easily intercept and blockade navigations dynamically.
30
+ - **Click Hijacking**: Automatically binds to HTML5 PushState and catches `data-route` click events!
39
31
 
40
- ### 2. ⚡ Event Bus (`ylsoo.events`)
41
- An enterprise Publisher/Subscriber mechanism to handle inter-component state within Ylsoo frontends or microservices.
42
32
  ```javascript
43
- // Component A (Subscribes)
44
- const unsubscribe = ylsoo.events.on('user:login', (user) => {
45
- console.log('Welcome back,', user.name);
33
+ // 1. Build an Authentication Middleware Guard
34
+ ylsoo.router.beforeEach((to, from, next) => {
35
+ if (to.includes('admin') && !loggedIn) next(false); // Halt routing
46
36
  });
47
37
 
48
- // Component B (Publishes)
49
- ylsoo.events.emit('user:login', { name: 'Admin' });
38
+ // 2. Configure Dynamic Deep Routes
39
+ ylsoo.router.add('/users/:id/billing', (route) => {
40
+ console.log('Loading Billing For User:', route.params.id);
41
+ });
50
42
 
51
- // Listen exactly once
52
- ylsoo.events.once('system:boot', bootFunction);
43
+ ylsoo.router.start();
53
44
  ```
54
45
 
55
- ### 3. 🌐 Ylsoo Request Engine (`ylsoo.http`)
56
- A robust wrapper around the versatile `fetch` API. It handles JSON stringification, applies custom headers, parses JSON, and safely formats errors automatically.
46
+ ### 2. 🎛️ Deterministic A/B Flags (`ylsoo.feature`)
47
+ Not just a switch. A true matrix evaluation engine utilizing cryptographic hashing to guarantee specific users continuously load the exact same "random" feature buckets.
48
+
57
49
  ```javascript
58
- async function fetchUserData() {
59
- try {
60
- const data = await ylsoo.http.get('https://api.ylsoo.com/v1/user/me');
61
- } catch (error) {
62
- ylsoo.logger.error('Failed to fetch user', error);
63
- }
50
+ // Force the dashboard to turn on ONLY for:
51
+ // 1) Exactly 25% of traffic
52
+ // 2) Users whose attributes dictate they live in the UK
53
+ ylsoo.feature.setFlag('beta_dashboard', {
54
+ enabled: true,
55
+ rolloutPercentage: 25,
56
+ conditions: { country: 'UK' }
57
+ });
58
+
59
+ // Execution check during login
60
+ const userContext = { userId: "uuid-123", attributes: { country: 'UK' }};
61
+
62
+ if (await ylsoo.feature.evaluate('beta_dashboard', userContext)) {
63
+ console.log('User Granted Beta Access');
64
64
  }
65
65
  ```
66
66
 
67
- ### 4. 🧠 Ylsoo Memory Cache (`ylsoo.cache`)
68
- A volatile in-memory Map structure featuring native Time-To-Live (TTL) functionality.
67
+ ### 3. 🛡️ Resilience Core (`ylsoo.resilience`)
68
+ - **`withRetry(fn)`**: Wraps flaky API calls and repeats them on an exponential delay loop (e.g. 1s... 2s... 4s...) rather than immediately panicking.
69
+ - **`createBreaker(fn)`**: Operates a Circuit Breaker algorithm to instantly cut network traffic down if an upstream service goes offline, protecting your node instances from dead-locking.
70
+
71
+ ### 4. 🕐 Precise Time Formatter (`ylsoo.time`)
72
+ Completely strips the need for massive `moment.js` dependency packets. Quickly parses standard intervals.
69
73
  ```javascript
70
- // Cache an object for 5000 ms (5 seconds)
71
- ylsoo.cache.set('session', { id: 123 }, 5000);
72
- const session = ylsoo.cache.get('session');
74
+ ylsoo.time.format(Date.now(), "YYYY-MM-DD HH:mm:ss");
75
+ ylsoo.time.timeAgo(oldDate); // "5 minutes ago"
73
76
  ```
74
77
 
75
- ### 5. 🖥️ Ylsoo Console (`ylsoo.logger`)
76
- Formatted console utility employing native ANSI escape codes specifically designed for local backends.
78
+ ### 5. 🗄️ Strict Config Matrix (`ylsoo.config`)
79
+ A deep-merging configurations orchestrator. Implements `.freeze()` architecture to physically lock constants into memory, violently blocking any injected bad code downstream from maliciously altering your `API_KEYS`.
80
+
81
+ ### 6. 🗃️ Concurrency Queue (`ylsoo.createQueue`)
82
+ Need thousands of promises to compute, but executing them simultaneously throttles your CPU? Assign them to a limit.
77
83
  ```javascript
78
- ylsoo.logger.info('System initializing...');
79
- ylsoo.logger.success('Database connected successfully!');
80
- ylsoo.logger.warn('Rate limit approaching.');
81
- ylsoo.logger.error('Critical failure detected.');
84
+ const q = ylsoo.createQueue(5); // Throttle process to exactly 5 lanes
85
+ q.add(() => fetchBigData1());
86
+ q.add(() => fetchBigData2());
82
87
  ```
83
88
 
84
- ### 6. 🧰 Native Enterprise Utilies
85
- - **`ylsoo.sleep(ms)`**: Promise-based execution halter.
86
- - **`ylsoo.deepClone(obj)`**: Safely deep clones utilizing native modern standards like `structuredClone` when available.
87
- - **`ylsoo.debounce(func, wait)`**: High performance throttling mechanics.
88
- - **`ylsoo.isEmpty(val)`**: Semantic entity verification (detects empty Sets, Maps, Objects, Strings, Arrays).
89
- - **`ylsoo.capitalize(str)`**: Automatic string standardizer.
90
-
91
89
  ---
92
90
  <div align="center">
93
91
  <p>Built with ❤️ by <b>Ylsoo</b>.</p>
package/index.d.ts CHANGED
@@ -1,12 +1,11 @@
1
1
  /**
2
- * @ylsoo/core v2.0.0 Type Definitions
3
- * Cross-platform Enterprise SDK
2
+ * @ylsoo/core v2.2.0 Type Definitions
3
+ * Enterprise Cross-Platform SDK
4
4
  */
5
5
 
6
6
  declare module '@ylsoo/core' {
7
7
 
8
- // --- Core Modules ---
9
-
8
+ // --- Base Systems ---
10
9
  export class YlsooLogger {
11
10
  info(message: string | any): void;
12
11
  success(message: string | any): void;
@@ -21,72 +20,121 @@ declare module '@ylsoo/core' {
21
20
  clear(): void;
22
21
  }
23
22
 
24
- export interface YlsooHttpOptions {
25
- method?: string;
26
- headers?: Record<string, string>;
27
- body?: any;
28
- [key: string]: any;
29
- }
30
-
31
23
  export class YlsooHttp {
32
- request<T = any>(endpoint: string, options?: YlsooHttpOptions): Promise<T>;
33
- get<T = any>(endpoint: string, headers?: Record<string, string>): Promise<T>;
34
- post<T = any>(endpoint: string, body: any, headers?: Record<string, string>): Promise<T>;
24
+ request<T = any>(endpoint: string, options?: any): Promise<T>;
25
+ get<T = any>(endpoint: string, headers?: any): Promise<T>;
26
+ post<T = any>(endpoint: string, body: any, headers?: any): Promise<T>;
35
27
  }
36
28
 
37
- // --- Security Modules ---
38
-
29
+ // --- Security & Process ---
39
30
  export class YlsooCrypto {
40
- /** Base64 encodes a utf-8 string securely */
41
31
  encodeBase64(str: string): string;
42
-
43
- /** Base64 decodes a string */
44
32
  decodeBase64(base64: string): string;
45
-
46
- /** Natively generates a secure SHA-256 hash */
47
33
  hash(str: string): Promise<string>;
48
-
49
- /** Generates a cryptographically strong v4 UUID */
50
34
  uuid(): string;
51
35
  }
52
36
 
53
- // --- Event Modules ---
54
-
55
37
  export class YlsooEventBus {
56
- /** Subscribe to an event. Returns an unsubscribe function. */
57
38
  on(event: string, callback: (data?: any) => void): () => void;
58
-
59
- /** Unsubscribe from an event. */
60
39
  off(event: string, callback: (data?: any) => void): void;
61
-
62
- /** Publish an event to all subscribers. */
63
40
  emit(event: string, data?: any): void;
64
-
65
- /** Subscribe to an event, un-subscribing immediately after first emission. */
66
41
  once(event: string, callback: (data?: any) => void): void;
67
-
68
- /** clear all event listeners */
69
42
  clear(): void;
70
43
  }
71
44
 
72
- // --- Main Export ---
45
+ // --- State & Config ---
46
+ export class YlsooState {
47
+ setup(key: string, initialValue?: any): void;
48
+ get<T = any>(key: string): T;
49
+ set(key: string, value: any): void;
50
+ subscribe<T = any>(key: string, callback: (val: T) => void): () => void;
51
+ }
52
+
53
+ export class YlsooStorage {
54
+ set(key: string, value: any): void;
55
+ get<T = any>(key: string): T | null;
56
+ remove(key: string): void;
57
+ }
58
+
59
+ export class YlsooConfig {
60
+ setDefault(defaults: Record<string, any>): void;
61
+ applyEnvironment(envOverrides: Record<string, any>): void;
62
+ freeze(): void;
63
+ get<T = any>(key?: string | null): T;
64
+ }
65
+
66
+ export class YlsooFeatureFlags {
67
+ setFlag(flagName: string, rules: { enabled?: boolean, rolloutPercentage?: number, conditions?: Record<string, any> }): void;
68
+ evaluate(flagName: string, context?: { userId?: string, attributes?: Record<string, any> }): Promise<boolean>;
69
+ }
73
70
 
71
+ // --- Flow & Routers ---
72
+ export class YlsooRouter {
73
+ beforeEach(hook: (to: string, from: string, next: (confirm?: boolean) => void) => void): void;
74
+ add(path: string, handler: (route: { params: any, query: any, path: string }) => void): void;
75
+ setFallback(handler: (route: { path: string, query: any }) => void): void;
76
+ start(): void;
77
+ push(path: string): void;
78
+ }
79
+
80
+ export class YlsooResilience {
81
+ withRetry<T>(asyncFunction: () => Promise<T>, maxRetries?: number, baseDelayMs?: number): Promise<T>;
82
+ createBreaker<T>(asyncFunction: (...args: any[]) => Promise<T>, options?: any): (...args: any[]) => Promise<T>;
83
+ }
84
+
85
+ export class YlsooTaskQueue {
86
+ constructor(concurrencyLimit?: number);
87
+ add<T>(asyncTask: () => Promise<T>): Promise<T>;
88
+ get remaining(): number;
89
+ }
90
+
91
+ // --- Micro Utils ---
92
+ export class YlsooAnalytics {
93
+ configure(options: any): void;
94
+ track(eventName: string, metadata?: any): void;
95
+ }
96
+
97
+ export class Ylsoo18n {
98
+ load(locale: string, dict: Record<string, string>): void;
99
+ setLocale(locale: string): void;
100
+ t(key: string, variables?: Record<string, string>): string;
101
+ }
102
+
103
+ export class YlsooTime {
104
+ format(date: Date | number | string, formatStr?: string): string | null;
105
+ timeAgo(date: Date | number | string): string;
106
+ }
107
+
108
+ // --- Main Export ---
74
109
  export class YlsooCore {
75
110
  version: string;
76
111
 
77
- // Systems
78
- logger: YlsooLogger;
112
+ crypto: YlsooCrypto;
113
+ config: YlsooConfig;
114
+ router: YlsooRouter;
115
+ feature: YlsooFeatureFlags;
116
+
117
+ state: YlsooState;
79
118
  cache: YlsooCache;
119
+ storage: YlsooStorage;
120
+
80
121
  http: YlsooHttp;
81
- crypto: YlsooCrypto;
82
122
  events: YlsooEventBus;
123
+ resilience: YlsooResilience;
124
+ analytics: YlsooAnalytics;
125
+
126
+ logger: YlsooLogger;
127
+ time: YlsooTime;
128
+ i18n: Ylsoo18n;
83
129
 
84
- // Utilities
85
130
  sleep(ms: number): Promise<void>;
86
131
  deepClone<T>(obj: T): T;
87
132
  debounce<T extends (...args: any[]) => any>(func: T, wait: number): (...args: Parameters<T>) => void;
88
133
  isEmpty(value: any): boolean;
89
134
  capitalize(str: string): string;
135
+
136
+ validate(data: any, schema: Record<string, any>): boolean;
137
+ createQueue(limit?: number): YlsooTaskQueue;
90
138
  }
91
139
 
92
140
  const ylsoo: YlsooCore;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ylsoo/core",
3
- "version": "2.0.0",
3
+ "version": "2.0.1",
4
4
  "description": "Enterprise cross-platform SDK for Ylsoo projects",
5
5
  "main": "src/index.js",
6
6
  "types": "index.d.ts",
@@ -17,12 +17,13 @@
17
17
  "core",
18
18
  "enterprise",
19
19
  "sdk",
20
- "fetch",
21
- "logger",
22
- "cache",
23
- "crypto",
24
- "uuid",
25
- "events"
20
+ "router",
21
+ "feature-flags",
22
+ "ab-testing",
23
+ "circuit-breaker",
24
+ "retry",
25
+ "queue",
26
+ "time"
26
27
  ],
27
28
  "author": "Ylsoo",
28
29
  "license": "MIT",
@@ -0,0 +1,66 @@
1
+ class YlsooAnalytics {
2
+ constructor(httpEngine) {
3
+ this.http = httpEngine;
4
+ this.queue = [];
5
+ this.config = {
6
+ endpoint: null, // User must set this via configure()
7
+ batchSize: 10, // Flush after 10 events
8
+ flushInterval: 5000 // Or flush every 5 seconds
9
+ };
10
+
11
+ this.timer = null;
12
+ }
13
+
14
+ configure(options) {
15
+ this.config = { ...this.config, ...options };
16
+ this._startTimer();
17
+ }
18
+
19
+ /**
20
+ * Silently track an event
21
+ * @param {string} eventName
22
+ * @param {object} metadata
23
+ */
24
+ track(eventName, metadata = {}) {
25
+ this.queue.push({
26
+ event: eventName,
27
+ data: metadata,
28
+ timestamp: new Date().toISOString()
29
+ });
30
+
31
+ if (this.queue.length >= this.config.batchSize) {
32
+ this.flush();
33
+ }
34
+ }
35
+
36
+ async flush() {
37
+ if (this.queue.length === 0 || !this.config.endpoint) return;
38
+
39
+ const payload = [...this.queue];
40
+ this.queue = []; // clear early to prevent race conditions
41
+
42
+ try {
43
+ // Intentionally suppress errors to stay silent
44
+ await this.http.post(this.config.endpoint, { events: payload });
45
+ } catch(err) {
46
+ // Re-queue on fail
47
+ this.queue = [...payload, ...this.queue];
48
+ }
49
+ }
50
+
51
+ _startTimer() {
52
+ if (this.timer) clearInterval(this.timer);
53
+
54
+ // In Node or Browser, setInterval is standard
55
+ this.timer = setInterval(() => {
56
+ this.flush();
57
+ }, this.config.flushInterval);
58
+
59
+ // In node, unref the timer to prevent keeping the process alive
60
+ if (typeof this.timer.unref === 'function') {
61
+ this.timer.unref();
62
+ }
63
+ }
64
+ }
65
+
66
+ module.exports = { YlsooAnalytics };
@@ -0,0 +1,42 @@
1
+ class Ylsoo18n {
2
+ constructor() {
3
+ this.dictionary = {};
4
+ this.locale = 'en';
5
+ }
6
+
7
+ /**
8
+ * Load a language dictionary into memory
9
+ * @param {string} locale
10
+ * @param {object} dict
11
+ */
12
+ load(locale, dict) {
13
+ this.dictionary[locale] = dict;
14
+ }
15
+
16
+ setLocale(locale) {
17
+ this.locale = locale;
18
+ }
19
+
20
+ /**
21
+ * Translate a key and interpolate variables
22
+ * @param {string} key
23
+ * @param {object} variables
24
+ * @returns {string}
25
+ */
26
+ t(key, variables = {}) {
27
+ const dict = this.dictionary[this.locale];
28
+ if (!dict || !dict[key]) return key; // Fallback to raw key
29
+
30
+ let translation = dict[key];
31
+
32
+ // Interpolate: "Welcome {name}" -> "Welcome Admin"
33
+ Object.keys(variables).forEach(varKey => {
34
+ const regex = new RegExp(`{${varKey}}`, 'g');
35
+ translation = translation.replace(regex, variables[varKey]);
36
+ });
37
+
38
+ return translation;
39
+ }
40
+ }
41
+
42
+ module.exports = { Ylsoo18n };
@@ -0,0 +1,67 @@
1
+ class YlsooState {
2
+ constructor() {
3
+ this.state = {};
4
+ this.listeners = new Map();
5
+ }
6
+
7
+ /**
8
+ * Initializes or updates a specific state key
9
+ * @param {string} key
10
+ * @param {*} initialValue
11
+ */
12
+ setup(key, initialValue = null) {
13
+ if (!(key in this.state)) {
14
+ this.state[key] = initialValue;
15
+ this.listeners.set(key, new Set());
16
+ }
17
+ }
18
+
19
+ /**
20
+ * Retrieves the current value of a state key
21
+ * @param {string} key
22
+ */
23
+ get(key) {
24
+ return this.state[key];
25
+ }
26
+
27
+ /**
28
+ * Set a new value and trigger all subscribers
29
+ * @param {string} key
30
+ * @param {*} value
31
+ */
32
+ set(key, value) {
33
+ this.setup(key); // Ensure setup
34
+
35
+ // Only trigger if actually changed to prevent render loops
36
+ if (this.state[key] !== value) {
37
+ this.state[key] = value;
38
+ this.listeners.get(key).forEach(callback => {
39
+ try {
40
+ callback(value);
41
+ } catch (e) {
42
+ console.error(`[Ylsoo State] Error in listener for ${key}`, e);
43
+ }
44
+ });
45
+ }
46
+ }
47
+
48
+ /**
49
+ * Subscribe to changes on a specific key
50
+ * @param {string} key
51
+ * @param {Function} callback
52
+ * @returns {Function} Unsubscribe method
53
+ */
54
+ subscribe(key, callback) {
55
+ this.setup(key);
56
+ this.listeners.get(key).add(callback);
57
+
58
+ // Provide initial state immediately upon subscription
59
+ callback(this.state[key]);
60
+
61
+ return () => {
62
+ this.listeners.get(key).delete(callback);
63
+ };
64
+ }
65
+ }
66
+
67
+ module.exports = { YlsooState };
@@ -0,0 +1,99 @@
1
+ class YlsooStorage {
2
+ constructor(cryptoEngine) {
3
+ this.crypto = cryptoEngine; // Instance of YlsooCrypto
4
+ this.vaultPath = '.ylsoo-vault.json';
5
+
6
+ // Check environment (distinguish Node from Browser safely)
7
+ this.isBrowser = typeof window !== 'undefined' && typeof window.localStorage !== 'undefined';
8
+ }
9
+
10
+ // Very rudimentary AES-like masking to keep it zero-dependency and cross-platform
11
+ // without heavily relying on async SubtleCrypto which makes synchronous read/writes impossible here.
12
+ // We use Base64 padding for simplistic obfuscation here to keep the API synchronous.
13
+ // For true AES, it would require async/await API changes.
14
+ _obfuscate(str) {
15
+ return this.crypto.encodeBase64(str).split('').reverse().join('');
16
+ }
17
+
18
+ _deobfuscate(obf) {
19
+ const b64 = obf.split('').reverse().join('');
20
+ return this.crypto.decodeBase64(b64);
21
+ }
22
+
23
+ /**
24
+ * Sets a value securely
25
+ */
26
+ set(key, value) {
27
+ const raw = JSON.stringify(value);
28
+ const secureString = this._obfuscate(raw);
29
+ const secureKey = this._obfuscate(key);
30
+
31
+ if (this.isBrowser) {
32
+ globalThis.localStorage.setItem(secureKey, secureString);
33
+ } else {
34
+ this._writeNodeFile(secureKey, secureString);
35
+ }
36
+ }
37
+
38
+ /**
39
+ * Retrieves a secure value
40
+ */
41
+ get(key) {
42
+ const secureKey = this._obfuscate(key);
43
+ let secureString = null;
44
+
45
+ if (this.isBrowser) {
46
+ secureString = globalThis.localStorage.getItem(secureKey);
47
+ } else {
48
+ secureString = this._readNodeFile(secureKey);
49
+ }
50
+
51
+ if (!secureString) return null;
52
+
53
+ try {
54
+ const raw = this._deobfuscate(secureString);
55
+ return JSON.parse(raw);
56
+ } catch(e) {
57
+ return null;
58
+ }
59
+ }
60
+
61
+ /**
62
+ * Removes a secure key
63
+ */
64
+ remove(key) {
65
+ const secureKey = this._obfuscate(key);
66
+ if (this.isBrowser) {
67
+ globalThis.localStorage.removeItem(secureKey);
68
+ } else {
69
+ const map = this._getNodeMap();
70
+ delete map[secureKey];
71
+ require('fs').writeFileSync(this.vaultPath, JSON.stringify(map), 'utf8');
72
+ }
73
+ }
74
+
75
+ // -- Node.js Fallbacks --
76
+ _getNodeMap() {
77
+ try {
78
+ const fs = require('fs');
79
+ if (!fs.existsSync(this.vaultPath)) return {};
80
+ const raw = fs.readFileSync(this.vaultPath, 'utf8');
81
+ return JSON.parse(raw);
82
+ } catch (e) {
83
+ return {};
84
+ }
85
+ }
86
+
87
+ _writeNodeFile(key, val) {
88
+ const map = this._getNodeMap();
89
+ map[key] = val;
90
+ require('fs').writeFileSync(this.vaultPath, JSON.stringify(map), 'utf8');
91
+ }
92
+
93
+ _readNodeFile(key) {
94
+ const map = this._getNodeMap();
95
+ return map[key] || null;
96
+ }
97
+ }
98
+
99
+ module.exports = { YlsooStorage };
@@ -0,0 +1,54 @@
1
+ class YlsooConfig {
2
+ constructor() {
3
+ this.store = {};
4
+ this.isFrozen = false;
5
+ }
6
+
7
+ /**
8
+ * Defines a base configuration
9
+ * @param {object} defaults
10
+ */
11
+ setDefault(defaults) {
12
+ if (this.isFrozen) throw new Error('[Ylsoo Config] Cannot mutate after freezing.');
13
+ this.store = { ...defaults };
14
+ }
15
+
16
+ /**
17
+ * Deep merges environment overrides over defaults
18
+ * @param {object} envOverrides
19
+ */
20
+ applyEnvironment(envOverrides) {
21
+ if (this.isFrozen) throw new Error('[Ylsoo Config] Cannot mutate after freezing.');
22
+ this.store = this._deepMerge(this.store, envOverrides);
23
+ }
24
+
25
+ /**
26
+ * Locks the config so it cannot be altered during application runtime securely.
27
+ */
28
+ freeze() {
29
+ this.isFrozen = true;
30
+ Object.freeze(this.store);
31
+ }
32
+
33
+ /**
34
+ * Fetches the entire config or a specific key
35
+ * @param {string} key Optional
36
+ */
37
+ get(key = null) {
38
+ if (key) return this.store[key];
39
+ return this.store;
40
+ }
41
+
42
+ // Purely native deep merge logic
43
+ _deepMerge(target, source) {
44
+ for (const key of Object.keys(source)) {
45
+ if (source[key] instanceof Object && key in target) {
46
+ Object.assign(source[key], this._deepMerge(target[key], source[key]));
47
+ }
48
+ }
49
+ Object.assign(target || {}, source);
50
+ return target;
51
+ }
52
+ }
53
+
54
+ module.exports = { YlsooConfig };
@@ -0,0 +1,59 @@
1
+ class YlsooFeatureFlags {
2
+ constructor(cryptoEngine) {
3
+ this.crypto = cryptoEngine; // Need crypto to hash unique IDs for deterministic A/B testing
4
+ this.flags = {};
5
+ }
6
+
7
+ /**
8
+ * Register a feature flag ruleset
9
+ * @param {string} flagName
10
+ * @param {object} rules { enabled: boolean, rolloutPercentage: number, conditions: object }
11
+ */
12
+ setFlag(flagName, rules) {
13
+ this.flags[flagName] = {
14
+ enabled: false,
15
+ rolloutPercentage: 100, // 0 to 100
16
+ conditions: {}, // e.g. { country: 'US', tier: 'pro' }
17
+ ...rules
18
+ };
19
+ }
20
+
21
+ /**
22
+ * Evaluate if a feature is enabled for a specific context natively
23
+ * @param {string} flagName
24
+ * @param {object} context { userId: string, attributes: { country: 'US', tier: 'pro' }}
25
+ */
26
+ async evaluate(flagName, context = {}) {
27
+ const flag = this.flags[flagName];
28
+ if (!flag) return false;
29
+
30
+ // 1. Master Kill Switch check
31
+ if (flag.enabled === false) return false;
32
+
33
+ // 2. Fractional Rollout Evaluation
34
+ if (flag.rolloutPercentage < 100) {
35
+ if (!context.userId) return false; // Needs persistent ID for A/B rollout tracking
36
+
37
+ // We hash the flagName + userId so the same user ALWAYS gets the same result for a specific flag consistently.
38
+ const hashStr = await this.crypto.hash(`${flagName}-${context.userId}`);
39
+ // Natively convert first 8 chars of hex hash into an integer, modulus 100 to get a 0-99 distribution
40
+ const bucket = parseInt(hashStr.substring(0, 8), 16) % 100;
41
+
42
+ if (bucket >= flag.rolloutPercentage) {
43
+ return false;
44
+ }
45
+ }
46
+
47
+ // 3. Context Targeting Rules
48
+ for (const [key, expectedValue] of Object.entries(flag.conditions)) {
49
+ const userValue = (context.attributes || {})[key];
50
+ if (userValue !== expectedValue) {
51
+ return false; // Missed targeting matrix
52
+ }
53
+ }
54
+
55
+ return true;
56
+ }
57
+ }
58
+
59
+ module.exports = { YlsooFeatureFlags };
package/src/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @ylsoo/core v2.0.0
2
+ * @ylsoo/core v2.2.0
3
3
  * Enterprise utilities for both Node.js and the Web.
4
4
  */
5
5
 
@@ -9,28 +9,60 @@ const { YlsooCache } = require('./core/cache');
9
9
  const { YlsooCrypto } = require('./security/crypto');
10
10
  const { YlsooEventBus } = require('./events/bus');
11
11
  const { YlsooHelpers } = require('./utils/helpers');
12
+ const { YlsooState } = require('./core/state');
13
+ const { YlsooAnalytics } = require('./core/analytics');
14
+ const { Ylsoo18n } = require('./core/i18n');
15
+ const { YlsooStorage } = require('./core/storage');
16
+ const { YlsooValidator } = require('./validation/schema');
17
+
18
+ // V2.2.0 Ultra-Advanced Modules
19
+ const { YlsooRouter } = require('./router/domRouter');
20
+ const { YlsooFeatureFlags } = require('./engine/features');
21
+ const { YlsooResilience } = require('./resilience/breaker');
22
+ const { YlsooTaskQueue } = require('./utils/queue');
23
+ const { YlsooTime } = require('./utils/time');
24
+ const { YlsooConfig } = require('./engine/config');
12
25
 
13
26
  class YlsooCore {
14
27
  constructor() {
15
- this.version = '2.0.0';
28
+ this.version = '2.2.0';
16
29
 
17
- // Core Modules
18
- this.http = new YlsooHttp();
19
- this.logger = new YlsooLogger();
30
+ // Engine & Structure
31
+ this.crypto = new YlsooCrypto();
32
+ this.config = new YlsooConfig();
33
+ this.router = new YlsooRouter();
34
+ this.feature = new YlsooFeatureFlags(this.crypto);
35
+
36
+ // Memory & Data
37
+ this.state = new YlsooState();
20
38
  this.cache = new YlsooCache();
39
+ this.storage = new YlsooStorage(this.crypto);
40
+ this.validator = new YlsooValidator();
21
41
 
22
- // Advanced Modules
23
- this.crypto = new YlsooCrypto();
42
+ // Networking & Flow
43
+ this.http = new YlsooHttp();
24
44
  this.events = new YlsooEventBus();
45
+ this.resilience = new YlsooResilience();
46
+ this.analytics = new YlsooAnalytics(this.http);
47
+
48
+ // Helpers
49
+ this.logger = new YlsooLogger();
50
+ this.time = new YlsooTime();
51
+ this.i18n = new Ylsoo18n();
25
52
  this.helpers = new YlsooHelpers();
26
53
  }
27
54
 
28
- // --- Helper Proxies to keep backwards compatibility with v1.1.0 ---
55
+ // --- Helper Proxies to keep backwards compatibility ---
29
56
  sleep(ms) { return this.helpers.sleep(ms); }
30
57
  deepClone(obj) { return this.helpers.deepClone(obj); }
31
58
  debounce(func, wait) { return this.helpers.debounce(func, wait); }
32
59
  isEmpty(val) { return this.helpers.isEmpty(val); }
33
60
  capitalize(str) { return this.helpers.capitalize(str); }
61
+
62
+ validate(data, schema) { return this.validator.validate(data, schema); }
63
+
64
+ // Expose the raw Queue Class so developers can instantiate multiple queues if needed
65
+ createQueue(limit = 5) { return new YlsooTaskQueue(limit); }
34
66
  }
35
67
 
36
68
  module.exports = new YlsooCore();
@@ -0,0 +1,73 @@
1
+ class YlsooResilience {
2
+ /**
3
+ * Exponential backoff retry wrapper
4
+ * @param {Function} asyncFunction
5
+ * @param {number} maxRetries
6
+ * @param {number} baseDelayMs
7
+ */
8
+ async withRetry(asyncFunction, maxRetries = 3, baseDelayMs = 1000) {
9
+ let attempt = 0;
10
+ while (attempt <= maxRetries) {
11
+ try {
12
+ return await asyncFunction();
13
+ } catch (err) {
14
+ attempt++;
15
+ if (attempt > maxRetries) {
16
+ throw new Error(`[Ylsoo Resilience] Failed after ${maxRetries} retries. Final Error: ${err.message}`);
17
+ }
18
+
19
+ // Exponential backoff logic: 1s, 2s, 4s...
20
+ const delay = baseDelayMs * Math.pow(2, attempt - 1);
21
+ await new Promise(resolve => setTimeout(resolve, delay));
22
+ }
23
+ }
24
+ }
25
+
26
+ /**
27
+ * Creates a Circuit Breaker wrapper to prevent blasting dead APIs
28
+ * @param {Function} asyncFunction
29
+ * @param {object} options
30
+ */
31
+ createBreaker(asyncFunction, options = {}) {
32
+ const config = {
33
+ failureThreshold: 5, // Fail 5 times before breaking
34
+ resetTimeoutMs: 30000, // Keep broken for 30s before testing again
35
+ ...options
36
+ };
37
+
38
+ let failures = 0;
39
+ let state = 'CLOSED'; // CLOSED (working), OPEN (broken API), HALF_OPEN (testing)
40
+ let nextAttemptTimestamp = 0;
41
+
42
+ return async (...args) => {
43
+ if (state === 'OPEN') {
44
+ if (Date.now() >= nextAttemptTimestamp) {
45
+ state = 'HALF_OPEN';
46
+ } else {
47
+ throw new Error('[Ylsoo Circuit Breaker] Circuit is OPEN. Request dropped to protect upstream service.');
48
+ }
49
+ }
50
+
51
+ try {
52
+ const result = await asyncFunction(...args);
53
+
54
+ // Reset breaker on success
55
+ if (state === 'HALF_OPEN') {
56
+ state = 'CLOSED';
57
+ failures = 0;
58
+ }
59
+
60
+ return result;
61
+ } catch (err) {
62
+ failures++;
63
+ if (failures >= config.failureThreshold || state === 'HALF_OPEN') {
64
+ state = 'OPEN';
65
+ nextAttemptTimestamp = Date.now() + config.resetTimeoutMs;
66
+ }
67
+ throw err;
68
+ }
69
+ };
70
+ }
71
+ }
72
+
73
+ module.exports = { YlsooResilience };
@@ -0,0 +1,131 @@
1
+ class YlsooRouter {
2
+ constructor() {
3
+ this.routes = [];
4
+ this.middlewares = [];
5
+ this.currentRoute = null;
6
+ this.fallback = null;
7
+ this.isBrowser = typeof window !== 'undefined' && typeof window.history !== 'undefined';
8
+ }
9
+
10
+ /**
11
+ * Adds a global middleware hook
12
+ * @param {Function} hook (to, from, next)
13
+ */
14
+ beforeEach(hook) {
15
+ this.middlewares.push(hook);
16
+ }
17
+
18
+ /**
19
+ * Register a route mapping
20
+ * @param {string} path (e.g. "/users/:id")
21
+ * @param {Function} handler
22
+ */
23
+ add(path, handler) {
24
+ // Generate Regex for path parsing
25
+ const paramNames = [];
26
+ let regexPath = path.replace(/([:*])(\w+)/g, (full, colon, name) => {
27
+ paramNames.push(name);
28
+ return '([^/]+)';
29
+ });
30
+
31
+ // Allow wildcards
32
+ regexPath = regexPath.replace(/\*/g, '.*');
33
+
34
+ this.routes.push({
35
+ path,
36
+ regex: new RegExp(`^${regexPath}/?$`, 'i'),
37
+ paramNames,
38
+ handler
39
+ });
40
+ }
41
+
42
+ /**
43
+ * Set a 404 Not Found fallback route
44
+ * @param {Function} handler
45
+ */
46
+ setFallback(handler) {
47
+ this.fallback = handler;
48
+ }
49
+
50
+ /**
51
+ * Start the router engine, bind to HTML5 History and PopState
52
+ */
53
+ start() {
54
+ if (!this.isBrowser) return; // Silent fail in Node environments
55
+
56
+ // Bind back/forward buttons
57
+ window.addEventListener('popstate', () => {
58
+ this._navigate(window.location.pathname, false);
59
+ });
60
+
61
+ // Intercept clicks
62
+ document.body.addEventListener('click', (e) => {
63
+ const target = e.target.closest('a');
64
+ if (target && target.hasAttribute('data-route')) {
65
+ e.preventDefault();
66
+ this._navigate(target.getAttribute('href'));
67
+ }
68
+ });
69
+
70
+ // Run initial parse
71
+ this._navigate(window.location.pathname, false);
72
+ }
73
+
74
+ /**
75
+ * Navigate to a route manually
76
+ * @param {string} path
77
+ */
78
+ push(path) {
79
+ if (!this.isBrowser) return;
80
+ this._navigate(path, true);
81
+ }
82
+
83
+ async _navigate(urlPath, pushToHistory = true) {
84
+ const fromPath = this.currentRoute;
85
+
86
+ // Run middlewares
87
+ let halt = false;
88
+ const next = (confirm = true) => { if (confirm === false) halt = true; };
89
+
90
+ for (let mw of this.middlewares) {
91
+ await mw(urlPath, fromPath, next);
92
+ if (halt) return; // Middleware blocked navigation
93
+ }
94
+
95
+ // Match route
96
+ let matchedRoute = null;
97
+ let params = {};
98
+
99
+ for (let route of this.routes) {
100
+ const match = urlPath.match(route.regex);
101
+ if (match) {
102
+ matchedRoute = route;
103
+ route.paramNames.forEach((name, idx) => {
104
+ params[name] = match[idx + 1];
105
+ });
106
+ break;
107
+ }
108
+ }
109
+
110
+ if (pushToHistory && urlPath !== window.location.pathname) {
111
+ window.history.pushState(null, '', urlPath);
112
+ }
113
+
114
+ this.currentRoute = urlPath;
115
+
116
+ // Parse Query Params (Only in browser)
117
+ let query = {};
118
+ if (this.isBrowser && typeof window !== 'undefined') {
119
+ const url = new URL(window.location.href);
120
+ query = Object.fromEntries(url.searchParams.entries());
121
+ }
122
+
123
+ if (matchedRoute) {
124
+ matchedRoute.handler({ params, query, path: urlPath });
125
+ } else if (this.fallback) {
126
+ this.fallback({ path: urlPath, query });
127
+ }
128
+ }
129
+ }
130
+
131
+ module.exports = { YlsooRouter };
@@ -0,0 +1,50 @@
1
+ class YlsooTaskQueue {
2
+ /**
3
+ * Limit concurrency of massive promises automatically
4
+ * @param {number} concurrencyLimit
5
+ */
6
+ constructor(concurrencyLimit = 5) {
7
+ this.concurrencyLimit = concurrencyLimit;
8
+ this.activeCount = 0;
9
+ this.queue = [];
10
+ }
11
+
12
+ /**
13
+ * Add a function that returns a Promise to the queue
14
+ * @param {Function} asyncTask
15
+ * @returns {Promise<*>}
16
+ */
17
+ add(asyncTask) {
18
+ return new Promise((resolve, reject) => {
19
+ this.queue.push({
20
+ task: asyncTask,
21
+ resolve,
22
+ reject
23
+ });
24
+ this._next();
25
+ });
26
+ }
27
+
28
+ get remaining() {
29
+ return this.queue.length;
30
+ }
31
+
32
+ _next() {
33
+ if (this.activeCount >= this.concurrencyLimit || this.queue.length === 0) {
34
+ return;
35
+ }
36
+
37
+ this.activeCount++;
38
+ const { task, resolve, reject } = this.queue.shift();
39
+
40
+ task()
41
+ .then(resolve)
42
+ .catch(reject)
43
+ .finally(() => {
44
+ this.activeCount--;
45
+ this._next();
46
+ });
47
+ }
48
+ }
49
+
50
+ module.exports = { YlsooTaskQueue };
@@ -0,0 +1,46 @@
1
+ class YlsooTime {
2
+ /**
3
+ * Extremely lightweight date formatter (replaces heavy Moment.js)
4
+ * @param {Date|number|string} date
5
+ * @param {string} formatStr (e.g. "YYYY-MM-DD HH:mm:ss")
6
+ */
7
+ format(date, formatStr = "YYYY-MM-DD") {
8
+ const d = new Date(date);
9
+ if (isNaN(d.getTime())) return null;
10
+
11
+ const pad = (n) => String(n).padStart(2, '0');
12
+
13
+ return formatStr
14
+ .replace('YYYY', d.getFullYear())
15
+ .replace('YY', String(d.getFullYear()).slice(-2))
16
+ .replace('MM', pad(d.getMonth() + 1))
17
+ .replace('DD', pad(d.getDate()))
18
+ .replace('HH', pad(d.getHours()))
19
+ .replace('mm', pad(d.getMinutes()))
20
+ .replace('ss', pad(d.getSeconds()));
21
+ }
22
+
23
+ /**
24
+ * Fast "time ago" algorithm
25
+ * @param {Date|number|string} date
26
+ */
27
+ timeAgo(date) {
28
+ const d = new Date(date);
29
+ const seconds = Math.floor((new Date() - d) / 1000);
30
+
31
+ let interval = Math.floor(seconds / 31536000);
32
+ if (interval >= 1) return interval + " year" + (interval > 1 ? "s" : "") + " ago";
33
+ interval = Math.floor(seconds / 2592000);
34
+ if (interval >= 1) return interval + " month" + (interval > 1 ? "s" : "") + " ago";
35
+ interval = Math.floor(seconds / 86400);
36
+ if (interval >= 1) return interval + " day" + (interval > 1 ? "s" : "") + " ago";
37
+ interval = Math.floor(seconds / 3600);
38
+ if (interval >= 1) return interval + " hour" + (interval > 1 ? "s" : "") + " ago";
39
+ interval = Math.floor(seconds / 60);
40
+ if (interval >= 1) return interval + " minute" + (interval > 1 ? "s" : "") + " ago";
41
+
42
+ return Math.floor(seconds) + " seconds ago";
43
+ }
44
+ }
45
+
46
+ module.exports = { YlsooTime };
@@ -0,0 +1,53 @@
1
+ class YlsooValidator {
2
+ /**
3
+ * Validate an object against a strict schema mapping
4
+ * @param {*} data
5
+ * @param {object} schema
6
+ * @throws Error on validation failure
7
+ * @returns {boolean} true if valid
8
+ */
9
+ validate(data, schema) {
10
+ if (typeof data !== 'object' || data === null) {
11
+ throw new Error('[Ylsoo Validation] Target is not an object.');
12
+ }
13
+
14
+ for (const [key, rules] of Object.entries(schema)) {
15
+ const value = data[key];
16
+
17
+ // Handle raw type strings (e.g. { age: 'number' })
18
+ const type = typeof rules === 'string' ? rules : rules.type;
19
+
20
+ // Check required
21
+ const isRequired = typeof rules === 'object' ? rules.required !== false : true;
22
+ if (value === undefined || value === null) {
23
+ if (isRequired) throw new Error(`[Ylsoo Validation] Missing required key: ${key}`);
24
+ continue;
25
+ }
26
+
27
+ // Check Types
28
+ if (type === 'array') {
29
+ if (!Array.isArray(value)) throw new Error(`[Ylsoo Validation] Type mismatch. ${key} must be an array.`);
30
+ } else if (type === 'email') {
31
+ if (typeof value !== 'string' || !/^\S+@\S+\.\S+$/.test(value)) {
32
+ throw new Error(`[Ylsoo Validation] Type mismatch. ${key} must be a valid email.`);
33
+ }
34
+ } else if (type === 'object') {
35
+ if (typeof value !== 'object' || Array.isArray(value)) {
36
+ throw new Error(`[Ylsoo Validation] Type mismatch. ${key} must be an object.`);
37
+ }
38
+ // Recursive dive
39
+ if (rules.schema) {
40
+ this.validate(value, rules.schema);
41
+ }
42
+ } else {
43
+ if (typeof value !== type) {
44
+ throw new Error(`[Ylsoo Validation] Type mismatch. ${key} must be a ${type}.`);
45
+ }
46
+ }
47
+ }
48
+
49
+ return true;
50
+ }
51
+ }
52
+
53
+ module.exports = { YlsooValidator };