@cldmv/slothlet 2.7.1 → 2.9.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.
Files changed (39) hide show
  1. package/AGENT-USAGE.md +1 -1
  2. package/README.md +253 -1475
  3. package/dist/lib/helpers/als-eventemitter.mjs +4 -5
  4. package/dist/lib/helpers/api_builder/add_api.mjs +237 -0
  5. package/dist/lib/helpers/api_builder/analysis.mjs +522 -0
  6. package/dist/lib/helpers/api_builder/construction.mjs +457 -0
  7. package/dist/lib/helpers/api_builder/decisions.mjs +737 -0
  8. package/dist/lib/helpers/api_builder.mjs +16 -1567
  9. package/dist/lib/helpers/utilities.mjs +121 -0
  10. package/dist/lib/runtime/runtime-asynclocalstorage.mjs +44 -17
  11. package/dist/lib/runtime/runtime-livebindings.mjs +18 -3
  12. package/dist/lib/runtime/runtime.mjs +3 -3
  13. package/dist/slothlet.mjs +197 -547
  14. package/docs/API-RULES-CONDITIONS.md +508 -0
  15. package/{API-RULES.md → docs/API-RULES.md} +127 -72
  16. package/index.cjs +2 -1
  17. package/index.mjs +2 -1
  18. package/package.json +11 -9
  19. package/types/dist/lib/helpers/als-eventemitter.d.mts.map +1 -1
  20. package/types/dist/lib/helpers/api_builder/add_api.d.mts +60 -0
  21. package/types/dist/lib/helpers/api_builder/add_api.d.mts.map +1 -0
  22. package/types/dist/lib/helpers/api_builder/analysis.d.mts +189 -0
  23. package/types/dist/lib/helpers/api_builder/analysis.d.mts.map +1 -0
  24. package/types/dist/lib/helpers/api_builder/construction.d.mts +107 -0
  25. package/types/dist/lib/helpers/api_builder/construction.d.mts.map +1 -0
  26. package/types/dist/lib/helpers/api_builder/decisions.d.mts +213 -0
  27. package/types/dist/lib/helpers/api_builder/decisions.d.mts.map +1 -0
  28. package/types/dist/lib/helpers/api_builder.d.mts +5 -448
  29. package/types/dist/lib/helpers/api_builder.d.mts.map +1 -1
  30. package/types/dist/lib/helpers/utilities.d.mts +120 -0
  31. package/types/dist/lib/helpers/utilities.d.mts.map +1 -0
  32. package/types/dist/lib/runtime/runtime-asynclocalstorage.d.mts +7 -0
  33. package/types/dist/lib/runtime/runtime-asynclocalstorage.d.mts.map +1 -1
  34. package/types/dist/lib/runtime/runtime-livebindings.d.mts +8 -0
  35. package/types/dist/lib/runtime/runtime-livebindings.d.mts.map +1 -1
  36. package/types/dist/slothlet.d.mts +23 -13
  37. package/types/dist/slothlet.d.mts.map +1 -1
  38. package/types/index.d.mts +0 -1
  39. package/API-RULES-CONDITIONS.md +0 -367
package/README.md CHANGED
@@ -33,1438 +33,249 @@ The name might suggest we're taking it easy, but don't be fooled. **Slothlet del
33
33
 
34
34
  ---
35
35
 
36
- ## ✨ What's New in v2.x
36
+ ## ✨ What's New
37
37
 
38
- ### 🎯 **Complete Architectural Rewrite (v2.0)**
38
+ ### Latest: v2.9 (December 30, 2025)
39
39
 
40
- v2.0 represents a ground-up rewrite with enterprise-grade features:
40
+ - **Per-Request Context Isolation** - New `api.run()` and `api.scope()` methods for isolated context execution ([Documentation](https://github.com/CLDMV/slothlet/blob/master/docs/CONTEXT-PROPAGATION.md#per-request-context-isolation))
41
+ - API Builder Modularization - Improved maintainability and code organization
42
+ - [View Changelog](https://github.com/CLDMV/slothlet/blob/master/docs/changelog/v2.9.md)
41
43
 
42
- - **Universal Module Support**: Load both ESM (`.mjs`) and CommonJS (`.cjs`) files seamlessly
43
- - **Dual Runtime System**: Choose AsyncLocalStorage or live-bindings for context isolation
44
- - **4.3x Faster Startup**: Lazy mode achieves 564.17μs vs 2.45ms in eager mode
45
- - **Copy-Left Materialization**: Once loaded, modules stay materialized for optimal performance
46
- - **Zero Dependencies**: Pure Node.js implementation with no external dependencies
44
+ ### Recent Releases
47
45
 
48
- ### 🏗️ **Enhanced Architecture**
46
+ - **v2.8** - NPM security fixes and package workflow updates ([Changelog](https://github.com/CLDMV/slothlet/blob/master/docs/changelog/v2.8.md))
47
+ - **v2.7** - Security updates ([Changelog](https://github.com/CLDMV/slothlet/blob/master/docs/changelog/v2.7.md))
48
+ - **v2.6** - Hook System with 4 interceptor types ([Changelog](https://github.com/CLDMV/slothlet/blob/master/docs/changelog/v2.6.md))
49
+ - **v2.5** - Architectural consolidation and API consistency ([Changelog](https://github.com/CLDMV/slothlet/blob/master/docs/changelog/v2.5.md))
50
+ - **v2.4** - Multi-default export handling ([Changelog](https://github.com/CLDMV/slothlet/blob/master/docs/changelog/v2.4.md))
51
+ - **v2.3** - EventEmitter & Class Context Propagation ([Changelog](https://github.com/CLDMV/slothlet/blob/master/docs/changelog/v2.3.md))
52
+ - **v2.2** - Case preservation options ([Changelog](https://github.com/CLDMV/slothlet/blob/master/docs/changelog/v2.2.md))
53
+ - **v2.1** - Advanced sanitization patterns ([Changelog](https://github.com/CLDMV/slothlet/blob/master/docs/changelog/v2.1.md))
54
+ - **v2.0** - Complete Architectural Rewrite ([Changelog](https://github.com/CLDMV/slothlet/blob/master/docs/changelog/v2.0.md))
49
55
 
50
- - **Modular Design**: Organized into `engine/`, `modes/`, `runtime/`, and `helpers/`
51
- - **Live-Binding System**: Dynamic context and reference binding with runtime coordination
52
- - **Smart Function Naming**: Preserves original capitalization (`autoIP`, `parseJSON`, `getHTTPStatus`)
53
- - **Multi-Execution Environments**: Singleton, VM, worker, fork isolation modes (experimental)
54
-
55
- ### 🔧 **Advanced Sanitization Control** ⭐ NEW
56
-
57
- - **Custom API Naming**: Control how filenames become API property names through sanitize options
58
- - **Boundary Pattern Matching**: Use `**string**` patterns for precise transformations (`**url**` → `buildURLWithParams`)
59
- - **Glob Pattern Support**: Apply rules with wildcards (`*json*`, `auto*`, `http*`) for flexible naming control
60
- - **Case-Sensitive Rules**: Preserve important naming patterns (acronyms, technical terms, branding)
61
- - **Mixed Rule Types**: Combine exact matches, globs, and boundary patterns for sophisticated naming strategies
62
-
63
- ### 📊 **Performance Optimizations**
64
-
65
- - **Startup**: Lazy mode 4.3x faster (564.17μs vs 2.45ms)
66
- - **Function Calls**: Eager mode 1.1x faster (0.65μs vs 0.72μs) after materialization
67
- - **Memory**: On-demand loading scales with actual usage
68
- - **Predictability**: Consistent performance characteristics per mode
69
-
70
- ### 🔄 **Context Propagation (v2.3)** ⭐ NEW
71
-
72
- - **EventEmitter Context Propagation**: Automatic context preservation across EventEmitter callbacks using AsyncResource patterns
73
- - **Class Instance Context Propagation**: Automatic context preservation across class method calls with transparent wrapping
74
- - **AsyncResource Integration**: Production-ready context management following Node.js best practices
75
- - **Zero Configuration**: Works automatically with TCP servers, HTTP servers, and any EventEmitter-based patterns
76
-
77
- ### 🎣 **Hook System (v2.6.4)** ⭐ NEW
78
-
79
- - **3-Hook Types**: `before` (modify args or cancel), `after` (transform results), `always` (observe final result)
80
- - **Cross-Mode Compatibility**: Works seamlessly across all 4 combinations (eager/lazy × async/live)
81
- - **Pattern Matching**: Target specific functions or use wildcards (`math.*`, `*.add`, `**`)
82
- - **Priority Control**: Order hook execution with numeric priorities
83
- - **Runtime Control**: Enable/disable hooks at runtime, globally or by pattern
84
- - **Short-Circuit Support**: Cancel execution and return custom values from `before` hooks
85
-
86
- ---
87
-
88
- ## 🚀 Key Features
89
-
90
- ### 🎯 **Dual Loading Strategies**
91
-
92
- - **Eager Loading**: Immediate loading for maximum performance in production environments
93
- - **Lazy Loading**: Copy-left materialization with look-ahead proxies (4.3x faster startup, 1.1x slower calls after materialization)
94
-
95
- > [!IMPORTANT]
96
- > **Function Call Patterns:**
97
- >
98
- > - **Lazy Mode**: ALL function calls must be awaited (`await api.math.add(2, 3)`) due to materialization process
99
- > - **Eager Mode**: Functions behave as originally defined - sync functions are sync (`api.math.add(2, 3)`), async functions are async (`await api.async.process()`)
100
-
101
- ### ⚡ Performance Excellence
102
-
103
- - **📊 For comprehensive performance analysis, benchmarks, and recommendations, see [PERFORMANCE.md](https://github.com/CLDMV/slothlet/blob/HEAD/PERFORMANCE.md)**
104
-
105
- ### 🔧 **Smart API Management**
106
-
107
- - **Callable Interface**: Use `slothlet(options)` for direct API creation
108
- - **Smart Flattening**: Intelligent rules create clean APIs (`math/math.mjs` → `api.math`, `connection.mjs` → `api.connect()`)
109
- - **Intelligent Naming**: Dash-separated names convert automatically (`root-math.mjs` → `api.rootMath`)
110
- - **Function Name Preservation**: Maintains original capitalization (`auto-ip.mjs` with `autoIP` → `api.autoIP`)
111
- - **Hybrid Exports**: Support for callable APIs with methods, default + named exports, and mixed patterns
112
-
113
- > [!TIP]
114
- > **📁 For comprehensive examples of API flattening, naming conventions, and function preservation patterns, see the test modules in [api_tests/](https://github.com/CLDMV/slothlet/blob/HEAD/api_tests) and their documentation in [docs/api_tests/](https://github.com/CLDMV/slothlet/blob/HEAD/docs/api_tests)**
115
-
116
- > [!NOTE]
117
- > **🔍 For detailed technical documentation on API transformation rules:**
118
- >
119
- > - **[API-RULES.md](https://github.com/CLDMV/slothlet/blob/HEAD/API-RULES.md)** - Verified API transformation rules with examples and test cases
120
- > - **[API-RULES-CONDITIONS.md](https://github.com/CLDMV/slothlet/blob/HEAD/API-RULES-CONDITIONS.md)** - Complete technical reference of all conditional logic that controls API generation
121
-
122
- ### 🔗 **Advanced Binding System**
123
-
124
- - **Live Bindings**: Dynamic context and reference binding for runtime API mutation
125
- - **Context Isolation**: Dual runtime options for per-instance context isolation with seamless integration
126
- - **Copy-Left Preservation**: Materialized functions stay materialized, preserving performance gains
127
- - **Bubble-Up Updates**: Parent API synchronization ensures consistency across the API tree
128
- - **Mixed Module Support**: Seamlessly blend ESM and CommonJS modules in the same API
129
-
130
- ### 🛠 **Developer Experience**
131
-
132
- - **Enhanced Error Handling**: Clear JavaScript errors with module suggestions and descriptive errors (planned for v3.0.0)
133
- - **TypeScript-Friendly**: Comprehensive JSDoc annotations for excellent editor support with auto-generated declarations
134
- - **Configurable Debug**: Detailed logging for development and troubleshooting via CLI flags or environment variables
135
- - **Multiple Instances**: Parameter-based isolation for complex applications with instance ID management
136
- - **Development Checks**: Built-in environment detection with silent production behavior
137
-
138
- ### 🏗 **Architecture & Compatibility**
139
-
140
- - **ESM-First**: Built for modern JavaScript with full ES module support
141
- - **Universal Loading**: CommonJS and ESM files work together seamlessly
142
- - **Zero Dependencies**: Lightweight footprint with no external dependencies
143
- - **Cross-Platform**: Works seamlessly across all Node.js environments
144
- - **Extensible**: Modular architecture with flexible API composition patterns
145
-
146
- ---
147
-
148
- ## 📦 Installation
149
-
150
- ### Requirements
151
-
152
- - **Node.js v12.20.0 or higher** (for ESM support with `import`/`export`)
153
- - **Node.js v16.4.0 or higher** (recommended for AsyncLocalStorage runtime - `runtime: "async"`)
154
-
155
- > [!IMPORTANT]
156
- > **v2.x Runtime Options**: Slothlet v2.x supports two runtime systems:
157
- >
158
- > - **AsyncLocalStorage Runtime** (`runtime: "async"`) - Default, requires Node.js v16.4.0+ for context isolation
159
- > - **Live Bindings Runtime** (`runtime: "live"`) - Advanced system, works on Node.js v12.20.0+ without AsyncLocalStorage
160
- >
161
- > Both runtimes provide full live-binding capabilities with `self`, `context`, and `reference` support across ESM and CommonJS modules. Use `runtime: "live"` for older Node.js versions or advanced binding scenarios.
162
-
163
- ### Install
164
-
165
- ```bash
166
- npm install @cldmv/slothlet
167
- ```
168
-
169
- ---
170
-
171
- ## 🚀 Quick Start
172
-
173
- ### ESM (ES Modules)
174
-
175
- ```javascript
176
- import slothlet from "@cldmv/slothlet";
177
-
178
- // Direct usage - eager mode by default (auto-detects callable interface)
179
- const api = await slothlet({
180
- dir: "./api",
181
- context: { user: "alice" }
182
- });
183
-
184
- // Eager mode: Functions behave as originally defined
185
- const result = api.math.add(2, 3); // Sync function - no await needed
186
- const greeting = api("World"); // Instant if callable
187
-
188
- // Original async functions still need await in eager mode
189
- const asyncResult = await api.async.processData({ data: "async" });
190
-
191
- // Access both ESM and CJS modules seamlessly
192
- const esmResult = api.mathEsm.multiply(4, 5); // 20 (sync)
193
- const cjsResult = await api.mathCjs.divide(10, 2); // 5 (if originally async)
194
- ```
195
-
196
- ### CommonJS (CJS)
197
-
198
- ```javascript
199
- const slothlet = require("@cldmv/slothlet");
200
-
201
- // Same usage pattern works with CommonJS
202
- const api = await slothlet({
203
- dir: "./api",
204
- context: { env: "production" }
205
- });
206
-
207
- const result = api.math.multiply(4, 5); // 20
208
- const mixedResult = await api.interop.processData({ data: "test" }); // CJS+ESM interop
209
- ```
210
-
211
- ### Runtime Selection
212
-
213
- ```javascript
214
- // AsyncLocalStorage runtime (default) - requires Node.js v16.4.0+
215
- const apiAsync = await slothlet({
216
- dir: "./api",
217
- runtime: "async", // or "asynclocalstorage"
218
- context: { user: "alice" }
219
- });
220
-
221
- // Live bindings runtime - works on Node.js v12.20.0+
222
- const apiLive = await slothlet({
223
- dir: "./api",
224
- runtime: "live", // or "livebindings"
225
- context: { user: "bob" }
226
- });
227
-
228
- // Both provide identical live-binding capabilities
229
- import { self, context, reference } from "@cldmv/slothlet/runtime";
230
- // context.user is available in your modules regardless of runtime choice
231
- ```
232
-
233
- ### Lazy Loading Mode
234
-
235
- ```javascript
236
- import slothlet from "@cldmv/slothlet";
237
-
238
- // Lazy mode with copy-left materialization
239
- const api = await slothlet({
240
- mode: "lazy", // New preferred syntax
241
- dir: "./api",
242
- apiDepth: 3
243
- });
244
-
245
- // Or use legacy syntax (still supported)
246
- const apiLegacy = await slothlet({
247
- lazy: true, // Legacy syntax
248
- dir: "./api",
249
- apiDepth: 3
250
- });
251
-
252
- // First access: ~310μs (materialization overhead)
253
- const result1 = await api.math.add(2, 3);
254
-
255
- // Subsequent access: ~0.5μs (materialized function)
256
- const result2 = await api.math.add(5, 7); // 700x faster than first call!
257
- ```
258
-
259
- ### Advanced Configuration
260
-
261
- ```javascript
262
- import slothlet from "@cldmv/slothlet";
263
-
264
- const api = await slothlet({
265
- dir: "./api",
266
- mode: "eager", // New: Loading strategy (lazy/eager)
267
- engine: "singleton", // New: Execution environment
268
- api_mode: "auto", // API structure behavior
269
- apiDepth: Infinity, // Directory traversal depth
270
- debug: false, // Enable verbose logging
271
- context: {
272
- // Injected into live-binding
273
- user: "alice",
274
- env: "production",
275
- config: { timeout: 5000 }
276
- },
277
- reference: {
278
- // Merged into API root
279
- version: "2.0.0",
280
- helpers: {
281
- /* ... */
282
- }
283
- },
284
- sanitize: {
285
- // 🔧 NEW: Control API property naming
286
- lowerFirst: false, // Keep first character casing
287
- rules: {
288
- leave: ["parseJSON", "autoIP"], // Preserve exact names
289
- leaveInsensitive: ["*xml*"], // Case-insensitive preservation
290
- upper: ["**url**", "api", "http*"], // Force uppercase (including boundary patterns)
291
- lower: ["id", "uuid", "*id"] // Force lowercase
292
- }
293
- }
294
- });
295
- ```
296
-
297
- ### Sanitize Options Examples
298
-
299
- Transform module filenames into clean, professional API property names with sophisticated control:
300
-
301
- ```javascript
302
- // Without sanitize options (default behavior)
303
- const api = await slothlet({ dir: "./api" });
304
- // Files: build-url-with-params.mjs, parse-json-data.mjs, auto-ip.mjs
305
- // Result: api.buildUrlWithParams, api.parseJsonData, api.autoIp
306
-
307
- // With sanitize options (custom naming control)
308
- const api = await slothlet({
309
- dir: "./api",
310
- sanitize: {
311
- lowerFirst: false, // Keep first character casing
312
- preserveAllUpper: true, // Preserve identifiers like "COMMON_APPS"
313
- preserveAllLower: false, // Transform identifiers like "common_apps"
314
- rules: {
315
- leave: ["parseJSON"], // Exact match preservation (case-sensitive)
316
- leaveInsensitive: ["*xml*"], // Case-insensitive preservation
317
- upper: ["**url**", "ip", "http*"], // Force uppercase transformations
318
- lower: ["id", "*id"] // Force lowercase transformations
319
- }
320
- }
321
- });
322
- // Result: api.buildURLWithParams, api.parseJSON, api.autoIP
323
- ```
324
-
325
- **Comprehensive Sanitize Configuration:**
326
-
327
- ```javascript
328
- const api = await slothlet({
329
- dir: "./api",
330
- sanitize: {
331
- // Basic Options
332
- lowerFirst: true, // Default: lowercase first character for camelCase
333
- preserveAllUpper: true, // Keep "COMMON_APPS" unchanged
334
- preserveAllLower: false, // Transform "common_apps" → "commonApps"
335
-
336
- rules: {
337
- // Preserve exact matches (case-sensitive)
338
- leave: ["parseJSON", "autoIP", "getHTTPStatus"],
339
-
340
- // Preserve patterns (case-insensitive)
341
- leaveInsensitive: ["*xml*", "*html*"],
342
-
343
- // Force uppercase transformations
344
- upper: [
345
- "api", // Exact: "api" → "API"
346
- "http*", // Glob: "httpGet" → "HTTPGet"
347
- "**url**", // Boundary: "buildUrlPath" → "buildURLPath"
348
- "**json**" // Boundary: "parseJsonData" → "parseJSONData"
349
- ],
350
-
351
- // Force lowercase transformations
352
- lower: [
353
- "id", // Exact: "ID" → "id"
354
- "*id", // Glob: "userId" → "userid"
355
- "uuid*" // Glob: "UUIDGenerator" → "uuidGenerator"
356
- ]
357
- }
358
- }
359
- });
360
- ```
361
-
362
- **Sanitize Pattern Types:**
363
-
364
- - **Exact Match**: `"parseJSON"` - Matches exact string only
365
- - **Glob Patterns**:
366
- - `"*json*"` - Matches anywhere in string (`parseJsonData`)
367
- - `"auto*"` - Matches at start (`autoGenerateId`)
368
- - `"*id"` - Matches at end (`userId`)
369
- - **Boundary Patterns**:
370
- - `"**url**"` - Only matches when surrounded by characters (`buildUrlPath` ✓, `url` ✗)
371
- - `"**json**"` - Matches `parseJsonData` but not standalone `json`
372
- - **Case Control**:
373
- - `leave` - Case-sensitive exact preservation
374
- - `leaveInsensitive` - Case-insensitive preservation
375
- - `preserveAllUpper`/`preserveAllLower` - Automatic case detection
376
-
377
- **Advanced Pattern Examples:**
378
-
379
- ```javascript
380
- // File transformations with patterns:
381
- sanitizePathName("build-url-with-params", {
382
- rules: { upper: ["**url**"] }
383
- }); // → "buildURLWithParams"
384
-
385
- sanitizePathName("parse-json-data", {
386
- rules: { upper: ["**json**"] }
387
- }); // → "parseJSONData"
388
-
389
- sanitizePathName("get-http-status", {
390
- rules: { upper: ["http*"] }
391
- }); // → "getHTTPStatus"
392
-
393
- sanitizePathName("validate-user-id", {
394
- rules: { lower: ["*id"] }
395
- }); // → "validateUserid"
396
-
397
- sanitizePathName("XML_PARSER", {
398
- preserveAllUpper: true
399
- }); // → "XML_PARSER" (preserved)
400
- ```
401
-
402
- ### Multiple Instances
403
-
404
- In v2.x, each call to `slothlet(options)` automatically creates a new isolated instance with its own context and configuration:
405
-
406
- #### ESM (ES Modules)
407
-
408
- ```javascript
409
- import slothlet from "@cldmv/slothlet";
410
-
411
- // Each call creates a new isolated instance automatically
412
- const api1 = await slothlet({ dir: "./api1", context: { tenant: "alice" } });
413
- const api2 = await slothlet({ dir: "./api2", context: { tenant: "bob" } });
414
-
415
- // Instances are completely isolated
416
- console.log(api1.context.tenant); // "alice"
417
- console.log(api2.context.tenant); // "bob"
418
- ```
419
-
420
- #### CommonJS (CJS)
421
-
422
- ```javascript
423
- const slothlet = require("@cldmv/slothlet");
424
-
425
- // Each call creates a new isolated instance automatically
426
- const api1 = await slothlet({ dir: "./api1", context: { tenant: "alice" } });
427
- const api2 = await slothlet({ dir: "./api2", context: { tenant: "bob" } });
428
-
429
- // Instances are completely isolated with their own AsyncLocalStorage contexts
430
- console.log(api1.context.tenant); // "alice"
431
- console.log(api2.context.tenant); // "bob"
432
- ```
433
-
434
- > [!NOTE]
435
- > **v2.x Simplification**: Unlike v1.x which required query string parameters or `withInstanceId()` methods, v2.x automatically creates isolated instances with each `slothlet()` call, using your chosen runtime system (`async` or `live`) for complete context separation.
436
-
437
- ---
438
-
439
- ## 📚 API Reference
440
-
441
- ### Core Methods
442
-
443
- #### `slothlet(options)` ⇒ `Promise<object>`
444
-
445
- Creates and loads an API instance with the specified configuration.
446
-
447
- **Parameters:**
448
-
449
- | Param | Type | Description |
450
- | ------- | -------- | --------------------- |
451
- | options | `object` | Configuration options |
452
-
453
- **Returns:** `Promise<object>` - The bound API object
454
-
455
- **Options:**
456
-
457
- | Option | Type | Default | Description |
458
- | ----------- | --------- | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
459
- | `dir` | `string` | `"api"` | Directory to load API modules from. Can be absolute or relative path. If relative, resolved from process.cwd(). |
460
- | `lazy` | `boolean` | `false` | **Legacy** loading strategy - `true` for lazy loading (on-demand), `false` for eager loading (immediate). Use `mode` option instead. |
461
- | `mode` | `string` | - | **New** loading mode - `"lazy"` for on-demand loading, `"eager"` for immediate loading. Takes precedence over `lazy` option. Also supports execution modes for backward compatibility. |
462
- | `engine` | `string` | `"singleton"` | **New** execution environment mode - `"singleton"`, `"vm"`, `"worker"`, or `"fork"` |
463
- | `runtime` | `string` | `"async"` | Runtime binding system: `"async"` for AsyncLocalStorage-based context isolation (default, requires Node.js v16.4.0+), `"live"` for advanced live-binding system (works on Node.js v12.20.0+). Both provide full live-binding capabilities. |
464
- | `apiDepth` | `number` | `Infinity` | Directory traversal depth control - `0` for root only, `Infinity` for all levels |
465
- | `debug` | `boolean` | `false` | Enable verbose logging. Can also be set via `--slothletdebug` command line flag or `SLOTHLET_DEBUG=true` environment variable |
466
- | `api_mode` | `string` | `"auto"` | API structure behavior when root-level default functions exist:<br/>• `"auto"`: Automatically detects if root has default function export and creates callable API<br/>• `"function"`: Forces API to be callable (use when you have root-level default function exports)<br/>• `"object"`: Forces API to be object-only (use when you want object interface regardless of exports) |
467
- | `context` | `object` | `{}` | Context data object injected into live-binding `context` reference. Available to all loaded modules via `import { context } from "@cldmv/slothlet/runtime"` |
468
- | `reference` | `object` | `{}` | Reference object merged into the API root level. Properties not conflicting with loaded modules are added directly to the API |
469
- | `sanitize` | `object` | `{}` | **🔧 NEW**: Advanced filename-to-API transformation control. Options: `lowerFirst` (boolean), `preserveAllUpper` (boolean), `preserveAllLower` (boolean), `rules` object with `leave` (exact case-sensitive), `leaveInsensitive` (case-insensitive), `upper`/`lower` arrays. Supports exact matches, glob patterns (`*json*`, `http*`), and boundary patterns (`**url**` for surrounded matches only) |
470
-
471
- #### ✨ Current Option Format
472
-
473
- The option structure has been improved for better clarity:
474
-
475
- ```javascript
476
- // ✅ New recommended syntax
477
- const api = await slothlet({
478
- mode: "lazy", // Loading strategy: "lazy" | "eager"
479
- engine: "singleton", // Execution environment: "singleton" | "vm" | "worker" | "fork"
480
- dir: "./api"
481
- });
482
-
483
- // ✅ Legacy syntax (still fully supported)
484
- const api = await slothlet({
485
- lazy: true, // Boolean loading strategy
486
- mode: "singleton", // Execution environment (legacy placement)
487
- dir: "./api"
488
- });
489
-
490
- // ✅ Mixed usage (mode takes precedence)
491
- const api = await slothlet({
492
- lazy: false, // Will be overridden
493
- mode: "lazy", // Takes precedence - results in lazy loading
494
- engine: "singleton"
495
- });
496
- ```
497
-
498
- **Benefits of the new syntax:**
499
-
500
- - **Clearer separation**: `mode` for loading strategy, `engine` for execution environment
501
- - **Better discoverability**: String values are more self-documenting than boolean flags
502
- - **Future-proof**: Easier to extend with additional loading strategies
503
- - **Backward compatible**: All existing code continues to work unchanged
504
-
505
- #### `slothlet.getApi()` ⇒ `object`
506
-
507
- Returns the raw API object (Proxy or plain object).
508
-
509
- **Returns:** `function | object` - The raw API object or function
510
-
511
- #### `slothlet.getBoundApi()` ⇒ `object`
512
-
513
- Returns the bound API object with context and reference.
514
-
515
- **Returns:** `function | object` - The bound API object or function with live bindings and context
516
-
517
- #### `slothlet.isLoaded()` ⇒ `boolean`
518
-
519
- Returns true if the API is loaded.
520
-
521
- **Returns:** `boolean` - Whether the API has been loaded
522
-
523
- #### `slothlet.shutdown()` ⇒ `Promise<void>`
524
-
525
- Gracefully shuts down the API and performs comprehensive resource cleanup to prevent hanging processes.
526
-
527
- **Cleanup includes:**
528
- - Hook manager state and registered hooks
529
- - AsyncLocalStorage context and bindings
530
- - EventEmitter listeners and AsyncResource instances (including third-party libraries)
531
- - Instance data and runtime coordination
532
-
533
- **Returns:** `Promise<void>` - Resolves when shutdown is complete
534
-
535
- > [!IMPORTANT]
536
- > **🛡️ Process Cleanup**: The shutdown method now performs comprehensive cleanup of all EventEmitter listeners created after slothlet loads, including those from third-party libraries like pg-pool. This prevents hanging AsyncResource instances that could prevent your Node.js process from exiting cleanly.
537
-
538
- > [!NOTE]
539
- > **📚 For detailed API documentation with comprehensive parameter descriptions, method signatures, and examples, see [docs/API.md](https://github.com/CLDMV/slothlet/blob/HEAD/docs/API.md)**
540
-
541
- ### Live Bindings
542
-
543
- Access live-bound references in your API modules:
544
-
545
- ```javascript
546
- // Create API with reference functions
547
- const api = await slothlet({
548
- dir: "./api",
549
- reference: {
550
- md5: (str) => crypto.createHash("md5").update(str).digest("hex"),
551
- version: "2.0.0",
552
- utils: { format: (msg) => `[LOG] ${msg}` }
553
- }
554
- });
555
- ```
556
-
557
- ```javascript
558
- // In your API modules (ESM)
559
- import { self, context, reference } from "@cldmv/slothlet/runtime";
560
-
561
- export function myFunction() {
562
- console.log(context.user); // Access live context
563
- return self.otherModule.helper(); // Access other API modules
564
-
565
- // Reference functions are available directly on self
566
- const hash = self.md5("hello world"); // Access reference function
567
- console.log(self.version); // Access reference data
568
- }
569
-
570
- // Mixed module example (ESM accessing CJS)
571
- export function processData(data) {
572
- // Call a CJS module from ESM
573
- const processed = self.cjsModule.process(data);
574
-
575
- // Use reference utilities directly
576
- const logged = self.utils.format(`Processed: ${processed}`);
577
- return self.md5(logged); // Hash the result
578
- }
579
- ```
580
-
581
- ```javascript
582
- // In your CJS modules
583
- const { self, context, reference } = require("@cldmv/slothlet/runtime");
584
-
585
- function cjsFunction(data) {
586
- console.log(context.env); // Access live context
587
-
588
- // Reference functions available directly on self
589
- const hash = self.md5(data); // Direct access to reference function
590
-
591
- return self.esmModule.transform(hash); // Access ESM modules from CJS
592
- }
593
-
594
- module.exports = { cjsFunction };
595
- ```
596
-
597
- ### EventEmitter Context Propagation
598
-
599
- Slothlet automatically preserves AsyncLocalStorage context across all EventEmitter callbacks using Node.js AsyncResource patterns. This ensures your API modules maintain full context access in event handlers without any configuration.
600
-
601
- ```javascript
602
- // api/tcp-server.mjs - Your API module
603
- import { self, context } from "@cldmv/slothlet/runtime";
604
- import net from "node:net";
605
-
606
- export function createTcpServer() {
607
- const server = net.createServer();
608
-
609
- // Connection handler maintains full context automatically
610
- server.on("connection", (socket) => {
611
- console.log(`User: ${context.user}`); // ✅ Context preserved
612
- console.log(`API keys: ${Object.keys(self).length}`); // ✅ Full API access
613
-
614
- // Socket data handler also maintains context automatically
615
- socket.on("data", (data) => {
616
- console.log(`Session: ${context.session}`); // ✅ Context preserved
617
- console.log(`Processing for: ${context.user}`); // ✅ Context preserved
618
-
619
- // Full API access in nested event handlers
620
- const processed = self.dataProcessor.handle(data.toString());
621
- socket.write(processed);
622
- });
623
-
624
- socket.on("error", (err) => {
625
- // Error handlers also maintain context
626
- self.logger.error(`Error for user ${context.user}: ${err.message}`);
627
- });
628
- });
629
-
630
- return server;
631
- }
632
-
633
- export function startServer(port = 3000) {
634
- const server = createTcpServer();
635
- server.listen(port);
636
- return server;
637
- }
638
- ```
639
-
640
- ```javascript
641
- // Usage in your application
642
- import slothlet from "@cldmv/slothlet";
643
-
644
- const api = await slothlet({
645
- dir: "./api",
646
- context: { user: "alice", session: "tcp-session" }
647
- });
648
-
649
- // Start the server - all event handlers will have full context
650
- const server = api.startServer(8080);
651
- console.log("TCP server started with context preservation");
652
- ```
653
-
654
- **Key Benefits:**
655
-
656
- - ✅ **Automatic**: No configuration needed - works transparently in all API modules
657
- - ✅ **Complete Context**: Full `context` object and `self` API access in all event handlers
658
- - ✅ **Nested Events**: Works with any depth of EventEmitter nesting (server → socket → custom emitters)
659
- - ✅ **Universal Support**: All EventEmitter methods (`on`, `once`, `addListener`) are automatically context-aware
660
- - ✅ **Production Ready**: Uses Node.js AsyncResource patterns for reliable context propagation
661
- - ✅ **Clean Shutdown**: Automatically cleans up all AsyncResource instances during shutdown to prevent hanging processes
662
- - ✅ **Zero Overhead**: Only wraps listeners when context is active, minimal performance impact
663
-
664
- > [!TIP]
665
- > **Automatic Context Propagation**: EventEmitter context propagation works automatically in both lazy and eager modes. TCP servers, HTTP servers, custom EventEmitters, and any other event-driven patterns in your API modules will maintain full slothlet context and API access without any code changes.
666
-
667
- ### Class Instance Context Propagation
668
-
669
- Slothlet automatically preserves AsyncLocalStorage context across all class instance method calls. When your API functions return class instances, slothlet wraps them transparently to ensure all method calls maintain full context access.
670
-
671
- ```javascript
672
- // api/data-processor.mjs - Your API module
673
- import { self, context } from "@cldmv/slothlet/runtime";
674
-
675
- class DataProcessor {
676
- constructor(config) {
677
- this.config = config;
678
- }
679
-
680
- process(data) {
681
- // Context automatically available in all methods
682
- console.log(`Processing for user: ${context.user}`); // ✅ Context preserved
683
- console.log(`Request ID: ${context.requestId}`); // ✅ Context preserved
684
-
685
- // Full API access in class methods
686
- const validated = self.validator.check(data);
687
- return this.transform(validated);
688
- }
689
-
690
- transform(data) {
691
- // Context preserved in nested method calls
692
- console.log(`Transforming for: ${context.user}`); // ✅ Context preserved
693
-
694
- // Call other API modules from class methods
695
- return self.utils.format(data);
696
- }
697
- }
698
-
699
- export function createProcessor(config) {
700
- // Return class instance - slothlet automatically wraps it
701
- return new DataProcessor(config);
702
- }
703
- ```
704
-
705
- ```javascript
706
- // Usage in your application
707
- import slothlet from "@cldmv/slothlet";
708
-
709
- const api = await slothlet({
710
- dir: "./api",
711
- context: { user: "alice", requestId: "req-123" }
712
- });
713
-
714
- // Create processor instance - all methods will have full context
715
- const processor = api.createProcessor({ format: "json" });
716
-
717
- // All method calls maintain context automatically
718
- const result = processor.process({ data: "test" });
719
- console.log("Processing completed with context preservation");
720
- ```
721
-
722
- **Key Benefits:**
723
-
724
- - ✅ **Automatic**: Class instances returned from API functions are automatically context-aware
725
- - ✅ **Transparent**: No code changes needed - works with existing class patterns
726
- - ✅ **Complete Context**: Full `context` object and `self` API access in all class methods
727
- - ✅ **Nested Methods**: Context preserved across method chains and internal calls
728
- - ✅ **Constructor Support**: Context preserved for both function calls and `new` constructor usage
729
- - ✅ **Performance Optimized**: Method wrapping is cached to avoid overhead on repeated calls
730
-
731
- > [!TIP]
732
- > **Universal Class Support**: Any class instance returned from your API functions automatically maintains slothlet context. This includes database models, service classes, utility classes, and any other object-oriented patterns in your codebase.
733
-
734
- ### Hook System
735
-
736
- Slothlet provides a powerful hook system for intercepting, modifying, and observing API function calls. Hooks work seamlessly across all loading modes (eager/lazy) and runtime types (async/live).
737
-
738
- #### Hook Configuration
739
-
740
- Hooks can be configured when creating a slothlet instance:
741
-
742
- ```javascript
743
- // Enable hooks (simple boolean)
744
- const api = await slothlet({
745
- dir: "./api",
746
- hooks: true // Enable all hooks with default pattern "**"
747
- });
748
-
749
- // Enable with custom pattern
750
- const api = await slothlet({
751
- dir: "./api",
752
- hooks: "database.*" // Only enable for database functions
753
- });
754
-
755
- // Full configuration object
756
- const api = await slothlet({
757
- dir: "./api",
758
- hooks: {
759
- enabled: true,
760
- pattern: "**", // Default pattern for filtering
761
- suppressErrors: false // Control error throwing behavior
762
- }
763
- });
764
- ```
765
-
766
- **Configuration Options:**
767
-
768
- - **`enabled`** (boolean): Enable or disable hook execution
769
- - **`pattern`** (string): Default pattern for filtering which functions hooks apply to
770
- - **`suppressErrors`** (boolean): Control error throwing behavior
771
- - `false` (default): Errors are sent to error hooks, THEN thrown (normal behavior)
772
- - `true`: Errors are sent to error hooks, BUT NOT thrown (returns `undefined`)
773
-
774
- **Error Suppression Behavior:**
775
-
776
- Error hooks **ALWAYS receive errors** regardless of this setting. The `suppressErrors` option only controls whether errors are thrown after error hooks execute.
777
-
778
- > [!IMPORTANT]
779
- > **Hooks Must Be Enabled**: Error hooks (and all hooks) only execute when `hooks.enabled: true`. If hooks are disabled, errors are thrown normally without any hook execution.
780
-
781
- When `suppressErrors: true`, errors are caught and sent to error hooks, but not thrown:
782
-
783
- ```javascript
784
- const api = await slothlet({
785
- dir: "./api",
786
- hooks: {
787
- enabled: true,
788
- pattern: "**",
789
- suppressErrors: true // Suppress all errors
790
- }
791
- });
792
-
793
- // Register error hook to monitor failures
794
- api.hooks.on(
795
- "error-monitor",
796
- "error",
797
- ({ path, error, source }) => {
798
- console.error(`Error in ${path}:`, error.message);
799
- // Log to monitoring service without crashing
800
- },
801
- { pattern: "**" }
802
- );
803
-
804
- // Function errors won't crash the application
805
- const result = await api.riskyOperation();
806
- if (result === undefined) {
807
- // Function failed but didn't throw
808
- console.log("Operation failed gracefully");
809
- }
810
- ```
811
-
812
- **Error Flow:**
813
-
814
- 1. Error occurs (in before hook, function, or after hook)
815
- 2. Error hooks execute and receive the error
816
- 3. **If `suppressErrors: false`** → Error is thrown (crashes if uncaught)
817
- 4. **If `suppressErrors: true`** → Error is NOT thrown, function returns `undefined`
818
-
819
- **What Gets Suppressed (when `suppressErrors: true`):**
820
-
821
- - ✅ Before hook errors → Sent to error hooks, NOT thrown
822
- - ✅ Function execution errors → Sent to error hooks, NOT thrown
823
- - ✅ After hook errors → Sent to error hooks, NOT thrown
824
- - ✅ Always hook errors → Sent to error hooks, never thrown (regardless of setting)
825
-
826
- > [!TIP]
827
- > **Use Case**: Enable `suppressErrors: true` for resilient systems where you want to monitor failures without crashing. Perfect for background workers, batch processors, or systems with comprehensive error monitoring.
828
-
829
- > [!CAUTION]
830
- > **Critical Operations**: For validation or authorization hooks where errors MUST stop execution, use `suppressErrors: false` (default) to ensure errors propagate normally.
831
-
832
- #### Hook Types
833
-
834
- **Four hook types with distinct responsibilities:**
835
-
836
- - **`before`**: Intercept before function execution
837
- - Modify arguments passed to functions
838
- - Cancel execution and return custom values (short-circuit)
839
- - Execute validation or logging before function runs
840
- - **`after`**: Transform results after successful execution
841
- - Transform function return values
842
- - Only runs if function executes (skipped on short-circuit)
843
- - Chain multiple transformations in priority order
844
- - **`always`**: Observe final result with full execution context
845
- - Always executes after function completes
846
- - Runs even when `before` hooks cancel execution or errors occur
847
- - Receives complete context: `{ path, result, hasError, errors }`
848
- - Cannot modify result (read-only observation)
849
- - Perfect for unified logging of both success and error scenarios
850
- - **`error`**: Monitor and handle errors
851
- - Receives detailed error context with source tracking
852
- - Error source types: 'before', 'function', 'after', 'always', 'unknown'
853
- - Includes error type, hook ID, hook tag, timestamp, and stack trace
854
- - Perfect for error monitoring, logging, and alerting
855
-
856
- #### Basic Usage
857
-
858
- ```javascript
859
- import slothlet from "@cldmv/slothlet";
860
-
861
- const api = await slothlet({
862
- dir: "./api",
863
- hooks: true // Enable hooks
864
- });
865
-
866
- // Before hook: Modify arguments
867
- api.hooks.on(
868
- "validate-input",
869
- "before",
870
- ({ path, args }) => {
871
- console.log(`Calling ${path} with args:`, args);
872
- // Return modified args or original
873
- return [args[0] * 2, args[1] * 2];
874
- },
875
- { pattern: "math.add", priority: 100 }
876
- );
877
-
878
- // After hook: Transform result
879
- api.hooks.on(
880
- "format-output",
881
- "after",
882
- ({ path, result }) => {
883
- console.log(`${path} returned:`, result);
884
- // Return transformed result
885
- return result * 10;
886
- },
887
- { pattern: "math.*", priority: 100 }
888
- );
889
-
890
- // Always hook: Observe final result with error context
891
- api.hooks.on(
892
- "log-execution",
893
- "always",
894
- ({ path, result, hasError, errors }) => {
895
- if (hasError) {
896
- console.log(`${path} failed with ${errors.length} error(s):`, errors);
897
- } else {
898
- console.log(`${path} succeeded with result:`, result);
899
- }
900
- // Return value ignored - read-only observer
901
- },
902
- { pattern: "**" } // All functions
903
- );
904
-
905
- // Call function - hooks execute automatically
906
- const result = await api.math.add(2, 3);
907
- // Logs: "Calling math.add with args: [2, 3]"
908
- // Logs: "math.add returned: 10" (4+6)
909
- // Logs: "Final result for math.add: 100" (10*10)
910
- // result === 100
911
- ```
912
-
913
- #### Short-Circuit Execution
914
-
915
- `before` hooks can cancel function execution and return custom values:
916
-
917
- ```javascript
918
- // Caching hook example
919
- const cache = new Map();
920
-
921
- api.hooks.on(
922
- "cache-check",
923
- "before",
924
- ({ path, args }) => {
925
- const key = JSON.stringify({ path, args });
926
- if (cache.has(key)) {
927
- console.log(`Cache hit for ${path}`);
928
- return cache.get(key); // Short-circuit: return cached value
929
- }
930
- // Return undefined to continue to function
931
- },
932
- { pattern: "**", priority: 1000 } // High priority
933
- );
934
-
935
- api.hooks.on(
936
- "cache-store",
937
- "after",
938
- ({ path, args, result }) => {
939
- const key = JSON.stringify({ path, args });
940
- cache.set(key, result);
941
- return result; // Pass through
942
- },
943
- { pattern: "**", priority: 100 }
944
- );
945
-
946
- // First call - executes function and caches
947
- await api.math.add(2, 3); // Computes and stores
948
-
949
- // Second call - returns cached value (function not executed)
950
- await api.math.add(2, 3); // Cache hit! No computation
951
- ```
952
-
953
- #### Pattern Matching
954
-
955
- Hooks support flexible pattern matching:
956
-
957
- ```javascript
958
- // Exact match
959
- api.hooks.on("hook1", "before", handler, { pattern: "math.add" });
960
-
961
- // Wildcard: all functions in namespace
962
- api.hooks.on("hook2", "before", handler, { pattern: "math.*" });
963
-
964
- // Wildcard: specific function in all namespaces
965
- api.hooks.on("hook3", "before", handler, { pattern: "*.add" });
966
-
967
- // Global: all functions
968
- api.hooks.on("hook4", "before", handler, { pattern: "**" });
969
- ```
970
-
971
- #### Priority and Chaining
972
-
973
- Multiple hooks execute in priority order (highest first):
974
-
975
- ```javascript
976
- // High priority - runs first
977
- api.hooks.on(
978
- "validate",
979
- "before",
980
- ({ args }) => {
981
- if (args[0] < 0) throw new Error("Negative numbers not allowed");
982
- return args;
983
- },
984
- { pattern: "math.*", priority: 1000 }
985
- );
986
-
987
- // Medium priority - runs second
988
- api.hooks.on("double", "before", ({ args }) => [args[0] * 2, args[1] * 2], { pattern: "math.*", priority: 500 });
989
-
990
- // Low priority - runs last
991
- api.hooks.on(
992
- "log",
993
- "before",
994
- ({ path, args }) => {
995
- console.log(`Final args for ${path}:`, args);
996
- return args;
997
- },
998
- { pattern: "math.*", priority: 100 }
999
- );
1000
- ```
1001
-
1002
- #### Runtime Control
1003
-
1004
- Enable and disable hooks at runtime:
1005
-
1006
- ```javascript
1007
- const api = await slothlet({ dir: "./api", hooks: true });
1008
-
1009
- // Add hooks
1010
- api.hooks.on("test", "before", handler, { pattern: "math.*" });
1011
-
1012
- // Disable all hooks
1013
- api.hooks.disable();
1014
- await api.math.add(2, 3); // No hooks execute
56
+ ---
1015
57
 
1016
- // Re-enable all hooks
1017
- api.hooks.enable();
1018
- await api.math.add(2, 3); // Hooks execute
58
+ ## 🚀 Key Features
1019
59
 
1020
- // Enable specific pattern only
1021
- api.hooks.disable();
1022
- api.hooks.enable("math.*"); // Only math.* pattern enabled
1023
- await api.math.add(2, 3); // math.* hooks execute
1024
- await api.other.func(); // No hooks execute
1025
- ```
60
+ ### 🎯 **Dual Loading Strategies**
1026
61
 
1027
- #### Hook Management
62
+ - **Eager Loading**: Immediate loading for maximum performance in production environments
63
+ - **Lazy Loading**: Copy-left materialization with look-ahead proxies (4.3x faster startup, 1.4x faster calls after materialization)
1028
64
 
1029
- ```javascript
1030
- // List registered hooks
1031
- const beforeHooks = api.hooks.list("before");
1032
- const afterHooks = api.hooks.list("after");
1033
- const allHooks = api.hooks.list(); // All types
65
+ > [!IMPORTANT]
66
+ > **Function Call Patterns:**
67
+ >
68
+ > - **Lazy Mode**: ALL function calls must be awaited (`await api.math.add(2, 3)`) due to materialization process
69
+ > - **Eager Mode**: Functions behave as originally defined - sync functions are sync (`api.math.add(2, 3)`), async functions are async (`await api.async.process()`)
1034
70
 
1035
- // Remove specific hook by ID
1036
- const id = api.hooks.on("temp", "before", handler, { pattern: "math.*" });
1037
- api.hooks.off(id);
71
+ ### Performance Excellence
1038
72
 
1039
- // Remove all hooks matching pattern
1040
- api.hooks.off("math.*");
73
+ - **2.9x faster startup** in lazy mode (4.89ms vs 14.29ms)
74
+ - **1.1x faster function calls** in eager mode (0.90μs vs 0.99μs)
75
+ - **Copy-left materialization**: Once loaded, modules stay materialized
76
+ - **Zero dependencies**: Pure Node.js implementation
1041
77
 
1042
- // Clear all hooks of a type
1043
- api.hooks.clear("before"); // Remove all before hooks
1044
- api.hooks.clear(); // Remove all hooks
1045
- ```
78
+ 📊 **For comprehensive performance analysis, benchmarks, and recommendations, see [docs/PERFORMANCE.md](https://github.com/CLDMV/slothlet/blob/master/docs/PERFORMANCE.md)**
1046
79
 
1047
- #### Error Handling
80
+ ### 🎣 **Hook System**
1048
81
 
1049
- Hooks have a special `error` type for observing function errors with detailed source tracking:
82
+ Powerful function interceptor system with 4 hook types:
1050
83
 
1051
- ```javascript
1052
- api.hooks.on(
1053
- "error-logger",
1054
- "error",
1055
- ({ path, error, source }) => {
1056
- console.error(`Error in ${path}:`, error.message);
1057
- console.error(`Source: ${source.type}`); // 'before', 'after', 'always', 'function', 'unknown'
84
+ - **`before`** - Modify arguments or cancel execution
85
+ - **`after`** - Transform return values
86
+ - **`always`** - Observe final results (read-only)
87
+ - **`error`** - Monitor and handle errors with detailed source tracking
1058
88
 
1059
- if (source.type === "function") {
1060
- console.error("Error occurred in function execution");
1061
- } else if (["before", "after", "always"].includes(source.type)) {
1062
- console.error(`Error occurred in ${source.type} hook:`);
1063
- console.error(` Hook ID: ${source.hookId}`);
1064
- console.error(` Hook Tag: ${source.hookTag}`);
1065
- }
89
+ Pattern matching, priority control, runtime enable/disable, and short-circuit support included.
1066
90
 
1067
- console.error(`Timestamp: ${source.timestamp}`);
1068
- console.error(`Stack trace:\n${source.stack}`);
91
+ 🎣 **For complete hook system documentation, see [docs/HOOKS.md](https://github.com/CLDMV/slothlet/blob/master/docs/HOOKS.md)**
1069
92
 
1070
- // Log to monitoring service with full context
1071
- // Error is re-thrown after all error hooks execute
1072
- },
1073
- { pattern: "**" }
1074
- );
93
+ ### 🔄 **Context Propagation**
1075
94
 
1076
- try {
1077
- await api.validateData({ invalid: true });
1078
- } catch (error) {
1079
- // Error hooks executed before this catch block
1080
- console.log("Caught error:", error);
1081
- }
1082
- ```
95
+ Automatic context preservation across all asynchronous boundaries:
1083
96
 
1084
- ##### Error Source Tracking
97
+ - **EventEmitter propagation**: Context maintained across all event callbacks
98
+ - **Class instance propagation**: Context preserved in class method calls
99
+ - **Zero configuration**: Works automatically with TCP servers, HTTP servers, and custom EventEmitters
1085
100
 
1086
- Error hooks receive detailed context about where errors originated:
101
+ 🔄 **For context propagation details, see [docs/CONTEXT-PROPAGATION.md](https://github.com/CLDMV/slothlet/blob/master/docs/CONTEXT-PROPAGATION.md)**
1087
102
 
1088
- **Source Types:**
103
+ ### 🔧 **Smart API Management**
1089
104
 
1090
- - `"function"`: Error occurred during function execution
1091
- - `"before"`: Error occurred in a before hook
1092
- - `"after"`: Error occurred in an after hook
1093
- - `"always"`: Error occurred in an always hook
1094
- - `"unknown"`: Error source could not be determined
105
+ - **Intelligent Flattening**: Clean APIs with automatic structure optimization (`math/math.mjs` → `api.math`)
106
+ - **Smart Naming**: Preserves original capitalization (`auto-ip.mjs` with `autoIP` → `api.autoIP`)
107
+ - **Advanced Sanitization**: Custom naming rules with glob and boundary patterns
108
+ - **Hybrid Exports**: Support for callable APIs with methods, default + named exports
1095
109
 
1096
- **Source Metadata:**
110
+ 🏗️ **For module structure examples, see [docs/MODULE-STRUCTURE.md](https://github.com/CLDMV/slothlet/blob/master/docs/MODULE-STRUCTURE.md)**
111
+ 📐 **For API flattening rules, see [docs/API-FLATTENING.md](https://github.com/CLDMV/slothlet/blob/master/docs/API-FLATTENING.md)**
1097
112
 
1098
- - `source.type`: Error source type (see above)
1099
- - `source.hookId`: Hook identifier (for hook errors)
1100
- - `source.hookTag`: Hook tag/name (for hook errors)
1101
- - `source.timestamp`: ISO timestamp when error occurred
1102
- - `source.stack`: Full stack trace
113
+ ### 🔗 **Advanced Binding System**
1103
114
 
1104
- **Example: Comprehensive Error Monitoring**
115
+ - **Live Bindings**: Dynamic context and reference binding for runtime API mutation
116
+ - **Context Isolation**: Dual runtime options (AsyncLocalStorage or live-bindings)
117
+ - **Mixed Module Support**: Seamlessly blend ESM and CommonJS modules
118
+ - **Copy-Left Preservation**: Materialized functions stay materialized
1105
119
 
1106
- ```javascript
1107
- const errorStats = {
1108
- function: 0,
1109
- before: 0,
1110
- after: 0,
1111
- always: 0,
1112
- byHook: {}
1113
- };
120
+ ### 🛠 **Developer Experience**
1114
121
 
1115
- api.hooks.on(
1116
- "error-analytics",
1117
- "error",
1118
- ({ path, error, source }) => {
1119
- // Track error source statistics
1120
- errorStats[source.type]++;
1121
-
1122
- if (source.hookId) {
1123
- if (!errorStats.byHook[source.hookTag]) {
1124
- errorStats.byHook[source.hookTag] = 0;
1125
- }
1126
- errorStats.byHook[source.hookTag]++;
1127
- }
1128
-
1129
- // Log detailed error info
1130
- console.error(`[${source.timestamp}] Error in ${path}:`);
1131
- console.error(` Type: ${source.type}`);
1132
- console.error(` Message: ${error.message}`);
1133
-
1134
- if (source.type === "function") {
1135
- // Function-level error - might be a bug in implementation
1136
- console.error(" Action: Review function implementation");
1137
- } else {
1138
- // Hook-level error - might be a bug in hook logic
1139
- console.error(` Action: Review ${source.hookTag} hook (${source.type})`);
1140
- }
1141
-
1142
- // Send to monitoring service
1143
- sendToMonitoring({
1144
- timestamp: source.timestamp,
1145
- path,
1146
- errorType: source.type,
1147
- hookId: source.hookId,
1148
- hookTag: source.hookTag,
1149
- message: error.message,
1150
- stack: source.stack
1151
- });
1152
- },
1153
- { pattern: "**" }
1154
- );
122
+ - **TypeScript-Friendly**: Comprehensive JSDoc annotations with auto-generated declarations
123
+ - **Configurable Debug**: Detailed logging via CLI flags or environment variables
124
+ - **Multiple Instances**: Parameter-based isolation for complex applications
125
+ - **Development Checks**: Built-in environment detection with silent production behavior
1155
126
 
1156
- // Later: Analyze error patterns
1157
- console.log("Error Statistics:", errorStats);
1158
- // {
1159
- // function: 5,
1160
- // before: 2,
1161
- // after: 1,
1162
- // always: 0,
1163
- // byHook: {
1164
- // "validate-input": 2,
1165
- // "format-output": 1
1166
- // }
1167
- // }
1168
- ```
127
+ ---
1169
128
 
1170
- **Important Notes:**
129
+ ## 📦 Installation
1171
130
 
1172
- - Errors from `before` and `after` hooks are re-thrown after error hooks execute
1173
- - Errors from `always` hooks are caught and logged but do NOT crash execution
1174
- - Error hooks themselves do not receive errors from other error hooks (no recursion)
1175
- - The `_hookSourceReported` flag prevents double-reporting of errors
131
+ ### Requirements
1176
132
 
1177
- #### Cross-Mode Compatibility
133
+ - **Node.js v16.4.0 or higher** (required for AsyncLocalStorage support)
1178
134
 
1179
- Hooks work identically across all configurations:
135
+ ### Install
1180
136
 
1181
- ```javascript
1182
- // Eager + AsyncLocalStorage
1183
- const api1 = await slothlet({ dir: "./api", lazy: false, runtime: "async", hooks: true });
1184
-
1185
- // Eager + Live Bindings
1186
- const api2 = await slothlet({ dir: "./api", lazy: false, runtime: "live", hooks: true });
1187
-
1188
- // Lazy + AsyncLocalStorage
1189
- const api3 = await slothlet({ dir: "./api", lazy: true, runtime: "async", hooks: true });
1190
-
1191
- // Lazy + Live Bindings
1192
- const api4 = await slothlet({ dir: "./api", lazy: true, runtime: "live", hooks: true });
1193
-
1194
- // Same hook code works with all configurations
1195
- [api1, api2, api3, api4].forEach((api) => {
1196
- api.hooks.on(
1197
- "universal",
1198
- "before",
1199
- ({ args }) => {
1200
- return [args[0] * 10, args[1] * 10];
1201
- },
1202
- { pattern: "math.add" }
1203
- );
1204
- });
137
+ ```bash
138
+ npm install @cldmv/slothlet
1205
139
  ```
1206
140
 
1207
- **Key Benefits:**
1208
-
1209
- - ✅ **Universal**: Works across all 4 mode/runtime combinations
1210
- - ✅ **Flexible**: Pattern matching with wildcards and priorities
1211
- - ✅ **Powerful**: Modify args, transform results, observe execution
1212
- - ✅ **Composable**: Chain multiple hooks with priority control
1213
- - ✅ **Dynamic**: Enable/disable at runtime globally or by pattern
1214
- - ✅ **Observable**: Separate hook types for different responsibilities
1215
-
1216
- ### API Mode Configuration
141
+ ---
1217
142
 
1218
- The `api_mode` option controls how slothlet handles root-level default function exports:
143
+ ## 🚀 Quick Start
1219
144
 
1220
- #### Auto-Detection (Recommended)
145
+ ### ESM (ES Modules)
1221
146
 
1222
147
  ```javascript
148
+ import slothlet from "@cldmv/slothlet";
149
+
150
+ // Direct usage - eager mode by default
1223
151
  const api = await slothlet({
1224
- api_mode: "auto" // Default - automatically detects structure
152
+ dir: "./api",
153
+ context: { user: "alice" }
1225
154
  });
1226
155
 
1227
- // If you have a root-level function export:
1228
- // root-function.mjs: export default function(name) { return `Hello, ${name}!` }
1229
- // Result: api("World") works AND api.otherModule.method() works
156
+ // Eager mode: Functions behave as originally defined
157
+ const result = api.math.add(2, 3); // Sync function - no await needed
158
+ const asyncResult = await api.async.processData({ data: "async" });
1230
159
 
1231
- // If you only have object exports:
1232
- // Result: api.math.add() works, api("World") doesn't exist
160
+ // Access both ESM and CJS modules seamlessly
161
+ const esmResult = api.mathEsm.multiply(4, 5);
162
+ const cjsResult = api.mathCjs.divide(10, 2);
1233
163
  ```
1234
164
 
1235
- #### Explicit Function Mode
165
+ ### CommonJS (CJS)
1236
166
 
1237
167
  ```javascript
168
+ const slothlet = require("@cldmv/slothlet");
169
+
170
+ // Same usage pattern works with CommonJS
1238
171
  const api = await slothlet({
1239
- api_mode: "function" // Force callable interface
172
+ dir: "./api",
173
+ context: { env: "production" }
1240
174
  });
1241
175
 
1242
- // Always creates callable API even without root default export
1243
- // Useful when you know you have root functions
1244
- const result = api("World"); // Calls root default function
1245
- const math = api.math.add(2, 3); // Also access other modules
176
+ const result = api.math.multiply(4, 5);
177
+ const mixedResult = await api.interop.processData({ data: "test" });
1246
178
  ```
1247
179
 
1248
- #### Explicit Object Mode
180
+ ### Lazy Loading Mode
1249
181
 
1250
182
  ```javascript
183
+ import slothlet from "@cldmv/slothlet";
184
+
185
+ // Lazy mode with copy-left materialization
1251
186
  const api = await slothlet({
1252
- api_mode: "object" // Force object-only interface
187
+ mode: "lazy", // Preferred syntax
188
+ dir: "./api",
189
+ apiDepth: 3
1253
190
  });
1254
191
 
1255
- // Always creates object interface even with root default export
1256
- // api("World") won't work, but api.rootFunction("World") will
1257
- const result = api.rootFunction("World"); // Access via property
1258
- const math = api.math.add(2, 3); // Normal module access
1259
- ```
1260
-
1261
- ---
1262
-
1263
- ## 🏗 Module Structure & Examples
1264
-
1265
- Slothlet supports sophisticated module organization patterns with seamless ESM/CJS interoperability:
1266
-
1267
- ### Root-Level Modules
1268
-
1269
- ```text
1270
- root-math.mjs → api.rootMath (dash-to-camelCase)
1271
- rootstring.mjs → api.rootstring
1272
- config.mjs → api.config
1273
- ```
1274
-
1275
- ### Filename-Folder Matching Modules
1276
-
1277
- ```text
1278
- math/math.mjs → api.math (filename matches folder)
1279
- string/string.mjs → api.string (filename matches folder)
1280
- util/util.cjs → api.util (CJS support with filename matching)
1281
- ```
1282
-
1283
- ### Multi-File Modules
1284
-
1285
- ```text
1286
- multi/
1287
- ├── alpha.mjs → api.multi.alpha
1288
- ├── beta.mjs → api.multi.beta
1289
- └── gamma.cjs → api.multi.gamma (mixed ESM/CJS)
1290
- ```
1291
-
1292
- ### Function-Based Modules
1293
-
1294
- ```text
1295
- funcmod/funcmod.mjs → api.funcmod() (callable function)
1296
- multi_func/
1297
- ├── alpha.mjs → api.multi_func.alpha()
1298
- └── beta.cjs → api.multi_func.beta() (CJS callable)
1299
- ```
1300
-
1301
- ### Mixed ESM/CJS Modules
1302
-
1303
- ```text
1304
- interop/
1305
- ├── esm-module.mjs → api.interop.esmModule
1306
- ├── cjs-module.cjs → api.interop.cjsModule
1307
- └── mixed.mjs → api.interop.mixed (calls both ESM and CJS)
1308
- ```
1309
-
1310
- ### Hybrid Export Patterns
1311
-
1312
- ```text
1313
- exportDefault/exportDefault.mjs → api.exportDefault() (callable with methods)
1314
- objectDefaultMethod/ → api.objectDefaultMethod() (object with default)
1315
- ```
1316
-
1317
- ### Nested Structure
1318
-
1319
- ```text
1320
- nested/
1321
- └── date/
1322
- ├── date.mjs → api.nested.date
1323
- └── util.cjs → api.nested.dateUtil
1324
- advanced/
1325
- ├── selfObject/ → api.advanced.selfObject
1326
- └── nest*/ → Various nesting examples
1327
- ```
1328
-
1329
- ### Utility Modules
1330
-
1331
- ```text
1332
- util/
1333
- ├── controller.mjs → api.util.controller
1334
- ├── extract.cjs → api.util.extract (CJS utility)
1335
- └── url/
1336
- ├── parser.mjs → api.util.url.parser
1337
- └── builder.cjs → api.util.url.builder (mixed)
1338
- ```
1339
-
1340
- ### Smart Function Naming Examples
1341
-
1342
- ```text
1343
- task/auto-ip.mjs (exports autoIP) → api.task.autoIP (preserves function name)
1344
- util/parseJSON.mjs → api.util.parseJSON (preserves JSON casing)
1345
- api/getHTTPStatus.mjs → api.api.getHTTPStatus (preserves HTTP casing)
1346
- ```
1347
-
1348
- ## 🏗️ API Flattening Rules
1349
-
1350
- Slothlet uses intelligent flattening rules to create clean, intuitive API structures. Understanding these rules helps you organize your modules for the best developer experience:
1351
-
1352
- ### 1. **Filename-Folder Matching** (Single Named Export)
1353
-
1354
- **When:** A file exports a single named export that matches the sanitized filename
1355
- **Why:** Avoids redundant nesting (`api.math.math.add()` → `api.math.add()`)
1356
- **Reasoning:** When file purpose matches folder purpose, eliminate the duplicate layer
1357
-
1358
- ```text
1359
- math/math.mjs (exports { math: {...} }) → api.math (flattened)
1360
- string/string.mjs (exports { string: {...} }) → api.string (flattened)
1361
- util/util.mjs (exports { util: {...} }) → api.util (flattened)
1362
- ```
1363
-
1364
- ### 2. **No Default Export + Only Named Exports** ⭐ NEW
1365
-
1366
- **When:** A file has **no default export** and **only named exports**
1367
- **Why:** The file acts as a pure function collection, not a module with a main export
1368
- **Reasoning:** If there's no "main thing" (default export), treat all functions as equals at the root level
1369
-
1370
- ```text
1371
- connection.mjs (exports { connect, disconnect, isConnected })
1372
- → api.connect(), api.disconnect(), api.isConnected()
1373
- Because: No default export = no main "connection" object needed
1374
-
1375
- app.mjs (exports { getAllApps, getCurrentApp, setApp })
1376
- → api.getAllApps(), api.getCurrentApp(), api.setApp()
1377
- Because: No default export = these are standalone utility functions
1378
-
1379
- state.mjs (exports { cloneState, emitLog, reset, update })
1380
- → api.cloneState(), api.emitLog(), api.reset(), api.update()
1381
- Because: No default export = treat as individual state utilities
1382
- ```
1383
-
1384
- ### 3. **Has Default Export** (Namespace Preservation)
1385
-
1386
- **When:** A file has a default export (with or without named exports)
1387
- **Why:** The default export indicates there's a "main thing" that should be the namespace
1388
- **Reasoning:** Default export signals intentional module structure that should be preserved
1389
-
1390
- ```text
1391
- config.mjs (exports default + named exports) → api.config.*
1392
- Because: Default export indicates a main config object with methods
1393
-
1394
- input.mjs (exports default + named exports) → api.input.*
1395
- Because: Default export indicates a main input handler with utilities
192
+ // First access: materialization overhead (~1.45ms average)
193
+ const result1 = await api.math.add(2, 3);
1396
194
 
1397
- volume.mjs (exports default + named exports) → api.volume.*
1398
- Because: Default export indicates a main volume controller with methods
195
+ // Subsequent access: materialized function (near-eager performance)
196
+ const result2 = await api.math.add(5, 7);
1399
197
  ```
1400
198
 
1401
- ### 4. **Root-Level Special Cases**
199
+ ### Hook System Example
1402
200
 
1403
- **When:** Files are at the root directory level (not in subfolders)
1404
- **Why:** Prevents accidental API pollution and maintains clear root structure
1405
- **Reasoning:** Root files are explicitly placed there and should maintain their intended naming
201
+ ```javascript
202
+ import slothlet from "@cldmv/slothlet";
1406
203
 
1407
- ```text
1408
- root-math.mjs → api.rootMath (namespace preserved)
1409
- Because: Explicitly named "root-math" = keep as intended namespace
204
+ const api = await slothlet({
205
+ dir: "./api",
206
+ hooks: true // Enable hooks
207
+ });
1410
208
 
1411
- rootstring.mjs → api.rootstring (namespace preserved)
1412
- Because: Root-level placement = developer wants this specific API structure
209
+ // Before hook: Modify arguments
210
+ api.hooks.on(
211
+ "validate",
212
+ "before",
213
+ ({ path, args }) => {
214
+ console.log(`Calling ${path} with args:`, args);
215
+ return [args[0] * 2, args[1] * 2];
216
+ },
217
+ { pattern: "math.add", priority: 100 }
218
+ );
1413
219
 
1414
- config.mjs → api.config (namespace preserved)
1415
- Because: Root config file = keep as clear config namespace, don't flatten
1416
- ```
220
+ // After hook: Transform result
221
+ api.hooks.on(
222
+ "format",
223
+ "after",
224
+ ({ path, result }) => {
225
+ console.log(`${path} returned:`, result);
226
+ return result * 10;
227
+ },
228
+ { pattern: "math.*", priority: 100 }
229
+ );
1417
230
 
1418
- ### 5. **Self-Referential Prevention**
231
+ // Always hook: Observe final result
232
+ api.hooks.on(
233
+ "observe",
234
+ "always",
235
+ ({ path, result, hasError }) => {
236
+ console.log(hasError ? `${path} failed` : `${path} succeeded`);
237
+ },
238
+ { pattern: "**" }
239
+ );
1419
240
 
1420
- **When:** A file would create circular/redundant nesting (`api.config.config`)
1421
- **Why:** Prevents infinite nesting and maintains clean API structure
1422
- **Reasoning:** When file/folder names match, assume they represent the same logical concept
241
+ // Error hook: Monitor errors with source tracking
242
+ api.hooks.on(
243
+ "error-logger",
244
+ "error",
245
+ ({ path, error, source }) => {
246
+ console.error(`Error in ${path}:`, error.message);
247
+ console.error(`Source: ${source.type}`); // 'before', 'after', 'function', 'always'
248
+ },
249
+ { pattern: "**" }
250
+ );
1423
251
 
1424
- ```text
1425
- config/config.mjs api.config (prevented: api.config.config.config...)
1426
- Because: config.mjs in config/ folder = same concept, use folder name only
252
+ // Call function - hooks execute automatically
253
+ const result = await api.math.add(2, 3);
1427
254
  ```
1428
255
 
1429
- ### 🎯 Flattening Decision Tree
1430
-
1431
- ```mermaid
1432
- flowchart TD
1433
- FILE[Module File] --> ROOT{Root Level?}
1434
-
1435
- ROOT -->|Yes| PRESERVE[Preserve Namespace<br/>api.rootMath, api.config]
1436
-
1437
- ROOT -->|No| SELFREFER{Self-Referential?}
1438
- SELFREFER -->|Yes| NAMESPACE[Use Namespace<br/>api.config]
1439
-
1440
- SELFREFER -->|No| HASDEFAULT{Has Default Export?}
1441
- HASDEFAULT -->|Yes| NAMESPACE
1442
-
1443
- HASDEFAULT -->|No| NAMEDONLY{Only Named Exports?}
1444
- NAMEDONLY -->|Yes| FLATTEN["Flatten All Named Exports<br/>api.connect, api.disconnect"]
1445
-
1446
- NAMEDONLY -->|No| SINGLENAMED{Single Named Export<br/>Matching Filename?}
1447
- SINGLENAMED -->|Yes| FLATTENSINGLE[Flatten Single Export<br/>api.math]
1448
- SINGLENAMED -->|No| NAMESPACE
1449
-
1450
- style FLATTEN fill:#e1f5fe,stroke:#0277bd,stroke-width:2px,color:#000
1451
- style FLATTENSINGLE fill:#e8f5e8,stroke:#2e7d32,stroke-width:2px,color:#000
1452
- style NAMESPACE fill:#fff3e0,stroke:#e65100,stroke-width:2px,color:#000
1453
- style PRESERVE fill:#fce4ec,stroke:#c2185b,stroke-width:2px,color:#000
1454
- ```
256
+ ---
1455
257
 
1456
- ### 🚀 Benefits of Smart Flattening
258
+ ## 📚 Configuration Options
259
+
260
+ | Option | Type | Default | Description |
261
+ | ------------------- | --------- | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
262
+ | `dir` | `string` | `"api"` | Directory to load API modules from (absolute or relative path) |
263
+ | `mode` | `string` | `"eager"` | **New** loading mode - `"lazy"` for on-demand loading, `"eager"` for immediate loading |
264
+ | `lazy` | `boolean` | `false` | **Legacy** loading strategy (use `mode` instead) |
265
+ | `engine` | `string` | `"singleton"` | Execution environment: `"singleton"`, `"vm"`, `"worker"`, or `"fork"` (experimental modes) |
266
+ | `runtime` | `string` | `"async"` | Runtime binding system: `"async"` for AsyncLocalStorage (requires Node.js v16.4.0+), `"live"` for live-bindings (works on Node.js v12.20.0+) |
267
+ | `apiDepth` | `number` | `Infinity` | Directory traversal depth - `0` for root only, `Infinity` for all levels |
268
+ | `debug` | `boolean` | `false` | Enable verbose logging (also via `--slothletdebug` flag or `SLOTHLET_DEBUG=true` env var) |
269
+ | `api_mode` | `string` | `"auto"` | API structure behavior: `"auto"` (detect), `"function"` (force callable), `"object"` (force object) |
270
+ | `allowApiOverwrite` | `boolean` | `true` | Allow `addApi()` to overwrite existing endpoints (`false` = prevent overwrites with warning) |
271
+ | `context` | `object` | `{}` | Context data injected into live-binding (available via `import { context } from "@cldmv/slothlet/runtime"`) |
272
+ | `reference` | `object` | `{}` | Reference object merged into API root level |
273
+ | `sanitize` | `object` | `{}` | Advanced filename-to-API transformation control with `lowerFirst`, `preserveAllUpper`, `preserveAllLower`, and `rules` (supports exact matches, glob patterns `*json*`, and boundary patterns `**url**`) |
274
+ | `hooks` | `mixed` | `false` | Enable hook system: `true` (enable all), `"pattern"` (enable with pattern), or object with `enabled`, `pattern`, `suppressErrors` options |
275
+
276
+ **For complete API documentation with detailed parameter descriptions and examples, see [docs/generated/API.md](https://github.com/CLDMV/slothlet/blob/master/docs/generated/API.md)**
1457
277
 
1458
- - **Cleaner APIs**: `api.connect()` instead of `api.connection.connect()`
1459
- _Why it matters:_ Reduces typing, improves readability, and matches how you'd naturally call connection functions
1460
- - **Intuitive Structure**: File organization matches API usage patterns
1461
- _Why it matters:_ Files with only utility functions flatten (no main export = no namespace needed), while files with main exports preserve their intended structure
1462
- - **Flexible Organization**: Mix flattened and nested patterns as needed
1463
- _Why it matters:_ You can organize files by purpose (`connection.mjs` for utilities, `config.mjs` for main objects) and slothlet automatically creates the right API structure
1464
- - **Developer Intent Respected**: Export structure signals your architectural intentions
1465
- _Why it matters:_ Default exports = "this is a main thing with methods", named exports only = "these are utility functions"
1466
- - **Backward Compatibility**: Existing APIs continue to work as expected
1467
- _Why it matters:_ The rules are additive - existing filename-matching and default export patterns still work exactly the same
278
+ ---
1468
279
 
1469
280
  ## 🔀 How Slothlet Works: Loading Modes Explained
1470
281
 
@@ -1592,59 +403,104 @@ flowchart TD
1592
403
 
1593
404
  ### Eager Mode (Default - Production Ready)
1594
405
 
406
+ **Best for:** Production environments, maximum runtime performance, predictable behavior
407
+
1595
408
  ```javascript
1596
409
  const api = await slothlet({ dir: "./api" }); // lazy: false by default
1597
410
 
1598
- // Functions behave as originally defined - no await needed for sync functions
1599
- const result = api.math.add(2, 3); // Sync function - direct call
1600
- const greeting = api("World"); // Instant if callable
1601
-
1602
- // Async functions still need await (as originally defined)
1603
- const asyncResult = await api.async.processData({ data: "test" }); // Original async function
1604
-
1605
- // ESM+CJS works seamlessly with native behavior
1606
- const mixed = api.interop.process({ data: "test" }); // Sync or async as defined
411
+ // Functions behave as originally defined
412
+ const result = api.math.add(2, 3); // Sync - no await needed
413
+ const asyncResult = await api.async.processData({ data: "test" }); // Async needs await
1607
414
  ```
1608
415
 
1609
416
  **Benefits:**
1610
417
 
1611
- - ✅ Fastest function calls (0.36μs average)
1612
- - ✅ Predictable performance
1613
- - ✅ No materialization delays
1614
- - ✅ Functions behave exactly as originally defined (sync stays sync, async stays async)
1615
- - ✅ Optimal for production environments
418
+ - ✅ Fastest function calls (0.90μs average)
419
+ - ✅ Predictable performance (no materialization delays)
420
+ - ✅ Functions behave exactly as originally defined
1616
421
 
1617
422
  ### Lazy Mode with Copy-Left Materialization (Production Ready)
1618
423
 
1619
- ```javascript
1620
- const api = await slothlet({ lazy: true, dir: "./api" });
424
+ **Best for:** Startup-sensitive applications, memory efficiency, loading only what you use
1621
425
 
1622
- // ALL function calls must be awaited in lazy mode (due to materialization)
1623
- const result1 = await api.math.add(2, 3); // First access: ~310μs (materialization)
1624
- const result2 = await api.math.add(5, 7); // Subsequent: ~0.5μs (materialized)
426
+ ```javascript
427
+ const api = await slothlet({ mode: "lazy", dir: "./api" });
1625
428
 
1626
- // Even originally sync functions need await in lazy mode
1627
- const greeting = await api("World"); // Callable interface also needs await
1628
- const syncResult = await api.string.format("Hello"); // Originally sync, but needs await
429
+ // ALL calls must be awaited (materialization process)
430
+ const result1 = await api.math.add(2, 3); // First: ~371μs (materialization)
431
+ const result2 = await api.math.add(5, 7); // Subsequent: 0.99μs (materialized)
1629
432
  ```
1630
433
 
1631
434
  **Benefits:**
1632
435
 
1633
- - ✅ 4.3x faster startup (564.17μs vs 2.45ms)
436
+ - ✅ 2.9x faster startup (4.89ms vs 14.29ms)
437
+ - ✅ Near-equal function call performance (0.99μs vs 0.90μs eager)
1634
438
  - ✅ Memory efficient (loads only what you use)
1635
439
  - ✅ Copy-left optimization (once loaded, stays loaded)
1636
- - ✅ Optimal for startup-sensitive applications
1637
- - ⚠️ All function calls require await (regardless of original sync/async nature)
1638
-
1639
- **Performance Summary:**
1640
440
 
1641
441
  > [!TIP]
1642
- > **Choose your loading strategy based on your needs:**
442
+ > **Choose your strategy:**
1643
443
  >
1644
- > - **Startup**: Lazy wins (4.3x faster - 564.17μs vs 2.45ms)
1645
- > - **Function calls**: Eager wins (1.1x faster - 0.65μs vs 0.72μs)
1646
- > - **Memory**: Lazy wins (loads only what you use)
1647
- > - **Predictability**: Eager wins (no materialization delays)
444
+ > - **Startup-sensitive?** Lazy mode (2.9x faster startup)
445
+ > - **Call-intensive?** Eager mode (1.1x faster calls)
446
+ > - **Need predictability?** Eager mode (no materialization delays)
447
+ > - **Large API, use subset?** → Lazy mode (memory efficient)
448
+
449
+ ---
450
+
451
+ ## 📊 Performance Analysis
452
+
453
+ For comprehensive performance benchmarks, analysis, and recommendations:
454
+
455
+ **📈 [See docs/PERFORMANCE.md](https://github.com/CLDMV/slothlet/blob/master/docs/PERFORMANCE.md)**
456
+
457
+ Key highlights:
458
+
459
+ - Detailed startup vs runtime performance comparison
460
+ - Memory usage analysis by loading mode
461
+ - Materialization cost breakdown by module type
462
+ - Real-world performance recommendations
463
+
464
+ [![CodeFactor]][codefactor_url] [![npms.io score]][npms_url]
465
+
466
+ [![npm unpacked size]][npm_size_url] [![Repo size]][repo_size_url]
467
+
468
+ ---
469
+
470
+ ## 📚 Documentation
471
+
472
+ ### Core Documentation
473
+
474
+ - **[API Documentation](https://github.com/CLDMV/slothlet/blob/master/docs/generated/API.md)** - Complete API reference with examples and detailed parameter descriptions
475
+ - **[Performance Analysis](https://github.com/CLDMV/slothlet/blob/master/docs/PERFORMANCE.md)** - Detailed benchmarks and recommendations
476
+ - **[Contributing Guide](CONTRIBUTING.md)** - How to contribute to the project
477
+ - **[Security Policy](SECURITY.md)** - Security guidelines and reporting
478
+ - **[Test Documentation](api_tests)** - Comprehensive test module examples
479
+
480
+ ### Technical Guides
481
+
482
+ - **[Hook System](https://github.com/CLDMV/slothlet/blob/master/docs/HOOKS.md)** - Complete hook system documentation with 4 hook types, pattern matching, and examples
483
+ - **[Context Propagation](https://github.com/CLDMV/slothlet/blob/master/docs/CONTEXT-PROPAGATION.md)** - EventEmitter and class instance context preservation
484
+ - **[Module Structure](https://github.com/CLDMV/slothlet/blob/master/docs/MODULE-STRUCTURE.md)** - Comprehensive module organization patterns and examples
485
+ - **[API Flattening](https://github.com/CLDMV/slothlet/blob/master/docs/API-FLATTENING.md)** - The 5 flattening rules with decision tree and benefits
486
+
487
+ ### API Rules & Transformation
488
+
489
+ - **[API Rules](https://github.com/CLDMV/slothlet/blob/master/docs/API-RULES.md)** - Systematically verified API transformation rules with real examples and test cases
490
+ - **[API Rules Conditions](https://github.com/CLDMV/slothlet/blob/master/docs/API-RULES-CONDITIONS.md)** - Complete technical reference of all 26 conditional statements that control API generation
491
+
492
+ ### Changelog
493
+
494
+ - **[v2.9](https://github.com/CLDMV/slothlet/blob/master/docs/changelog/v2.9.md)** - Per-Request Context Isolation & API Builder Modularization (December 30, 2025)
495
+ - **[v2.8](https://github.com/CLDMV/slothlet/blob/master/docs/changelog/v2.8.md)** - NPM security fixes and package workflow updates (December 26, 2025)
496
+ - **[v2.7](https://github.com/CLDMV/slothlet/blob/master/docs/changelog/v2.7.md)** - Hook System with 4 interceptor types (December 20, 2025)
497
+ - **[v2.6](https://github.com/CLDMV/slothlet/blob/master/docs/changelog/v2.6.md)** - Mode/Engine options and deep nested path fixes (November 10, 2025)
498
+ - **[v2.5](https://github.com/CLDMV/slothlet/blob/master/docs/changelog/v2.5.md)** - Architectural consolidation and API consistency (October 20, 2025)
499
+ - **[v2.4](https://github.com/CLDMV/slothlet/blob/master/docs/changelog/v2.4.md)** - Multi-default export handling with file-based naming (October 18, 2025)
500
+ - **[v2.3](https://github.com/CLDMV/slothlet/blob/master/docs/changelog/v2.3.md)** - EventEmitter & Class Context Propagation (October 16, 2025)
501
+ - **[v2.2](https://github.com/CLDMV/slothlet/blob/master/docs/changelog/v2.2.md)** - Case preservation options (preserveAllUpper/preserveAllLower) (October 14, 2025)
502
+ - **[v2.1](https://github.com/CLDMV/slothlet/blob/master/docs/changelog/v2.1.md)** - Advanced sanitization with boundary patterns (October 12, 2025)
503
+ - **[v2.0](https://github.com/CLDMV/slothlet/blob/master/docs/changelog/v2.0.md)** - Complete Architectural Rewrite (September 9, 2025)
1648
504
 
1649
505
  ---
1650
506
 
@@ -1664,27 +520,6 @@ try {
1664
520
  }
1665
521
  ```
1666
522
 
1667
- **Planned Enhanced Error Features (v3.0.0):**
1668
-
1669
- > [!TIP]
1670
- > **Coming Soon**: Enhanced error handling with descriptive messages and module suggestions:
1671
- >
1672
- > ```javascript
1673
- > try {
1674
- > await api.nonexistent.method();
1675
- > } catch (error) {
1676
- > console.error(error.message);
1677
- > // Planned: "Module 'nonexistent' not found in './api'. Available modules: math, string, util. Did you mean 'util'?"
1678
- > }
1679
- > ```
1680
- >
1681
- > **Planned Features:**
1682
- >
1683
- > - 🔍 **Module discovery**: Show available modules and suggest alternatives
1684
- > - 📍 **Context information**: Include directory path and configuration details
1685
- > - 🎯 **Actionable suggestions**: Provide specific guidance for resolution
1686
- > - 🚀 **Development mode**: Additional debugging information when debug flag is enabled
1687
-
1688
523
  ---
1689
524
 
1690
525
  ## 🔧 Production vs Development Modes
@@ -1712,8 +547,6 @@ try {
1712
547
  > - **Fork Mode**: Process isolation (in development)
1713
548
  > - **Child Mode**: Child process execution (in development)
1714
549
  > - **VM Mode**: Virtual machine context (in development)
1715
- >
1716
- > The experimental modes are located in `src/lib/engine/` and should not be used in production environments.
1717
550
 
1718
551
  ---
1719
552
 
@@ -1722,47 +555,26 @@ try {
1722
555
  ### Key Changes
1723
556
 
1724
557
  1. **Import paths**: `@cldmv/slothlet` instead of specific file paths
1725
- 2. **Configuration**: New options (`api_mode`, `context`, `reference`)
558
+ 2. **Configuration**: New options (`api_mode`, `context`, `reference`, `hooks`)
1726
559
  3. **Function names**: Enhanced preservation of original capitalization
1727
560
  4. **Module structure**: Mixed ESM/CJS support
1728
561
  5. **Live bindings**: Dual runtime system with AsyncLocalStorage and live-bindings options
562
+ 6. **Automatic instances**: No more query strings or `withInstanceId()` methods
1729
563
 
1730
564
  ### Migration Steps
1731
565
 
1732
566
  ```javascript
1733
- // v1.3.x - API creation (same pattern as v2.x)
1734
- import slothlet from "@cldmv/slothlet";
1735
- const api = await slothlet({
1736
- dir: "./api",
1737
- lazy: true
1738
- });
1739
-
1740
567
  // v1.3.x - Multiple instances required query strings or withInstanceId()
1741
568
  const api1 = await slothlet({ dir: "./api?instanceId=alice" });
1742
569
  const api2 = slothlet.withInstanceId("bob");
1743
570
  const bobApi = await api2({ dir: "./api" });
1744
571
 
1745
- // v2.0 - Same API creation, but automatic instance isolation
1746
- import slothlet from "@cldmv/slothlet";
1747
- const api = await slothlet({
1748
- dir: "./api",
1749
- lazy: true,
1750
- context: { user: "alice" }, // New: context injection
1751
- api_mode: "auto" // New: API mode control
1752
- });
1753
-
1754
- // v2.0 - Multiple instances automatically isolated (no query strings needed)
572
+ // v2.x - Automatic instance isolation (no query strings needed)
1755
573
  const api1 = await slothlet({ dir: "./api", context: { tenant: "alice" } });
1756
574
  const api2 = await slothlet({ dir: "./api", context: { tenant: "bob" } });
575
+ // Instances completely isolated with their own contexts
1757
576
  ```
1758
577
 
1759
- ### Performance Improvements
1760
-
1761
- - **Architectural optimizations** with copy-left materialization and AsyncLocalStorage integration
1762
- - **Zero dependencies** - pure Node.js implementation reduces overhead
1763
- - **Enhanced materialization** with copy-left optimization in lazy mode
1764
- - **Modular design** improves maintainability and potential optimization opportunities
1765
-
1766
578
  ---
1767
579
 
1768
580
  ## 🤝 Contributing
@@ -1775,46 +587,12 @@ We welcome contributions! The experimental modes in particular need development
1775
587
  4. **Provide feedback** on API design and performance
1776
588
  5. **Documentation improvements** are always appreciated
1777
589
 
1778
- See [CONTRIBUTING.md](https://github.com/CLDMV/slothlet/blob/HEAD/CONTRIBUTING.md) for detailed contribution guidelines.
590
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for detailed contribution guidelines.
1779
591
 
1780
592
  [![Contributors]][contributors_url] [![Sponsor shinrai]][sponsor_url]
1781
593
 
1782
594
  ---
1783
595
 
1784
- ## 📊 Performance Analysis
1785
-
1786
- For comprehensive performance benchmarks, analysis, and recommendations:
1787
-
1788
- **📈 [See PERFORMANCE.md](https://github.com/CLDMV/slothlet/blob/HEAD/PERFORMANCE.md)**
1789
-
1790
- Key highlights:
1791
-
1792
- - Detailed startup vs runtime performance comparison
1793
- - Memory usage analysis by loading mode
1794
- - Materialization cost breakdown by module type
1795
- - Real-world performance recommendations
1796
-
1797
- [![CodeFactor]][codefactor_url] [![npms.io score]][npms_url]
1798
-
1799
- [![npm unpacked size]][npm_size_url] [![Repo size]][repo_size_url]
1800
-
1801
- ---
1802
-
1803
- ## 📚 Documentation
1804
-
1805
- - **[API Documentation](https://github.com/CLDMV/slothlet/blob/HEAD/docs/API.md)** - Complete API reference with examples
1806
- - **[Performance Analysis](https://github.com/CLDMV/slothlet/blob/HEAD/PERFORMANCE.md)** - Detailed benchmarks and recommendations
1807
- - **[Contributing Guide](https://github.com/CLDMV/slothlet/blob/HEAD/CONTRIBUTING.md)** - How to contribute to the project
1808
- - **[Security Policy](https://github.com/CLDMV/slothlet/blob/HEAD/SECURITY.md)** - Security guidelines and reporting
1809
- - **[Test Documentation](https://github.com/CLDMV/slothlet/blob/HEAD/api_tests)** - Comprehensive test module examples
1810
-
1811
- ### 🔧 Technical Documentation
1812
-
1813
- - **[API Rules](https://github.com/CLDMV/slothlet/blob/HEAD/API-RULES.md)** - Systematically verified API transformation rules with real examples and test cases
1814
- - **[API Rules Conditions](https://github.com/CLDMV/slothlet/blob/HEAD/API-RULES-CONDITIONS.md)** - Complete technical reference of all 26 conditional statements that control API generation
1815
-
1816
- ---
1817
-
1818
596
  ## 🔗 Links
1819
597
 
1820
598
  - **npm**: [@cldmv/slothlet](https://www.npmjs.com/package/@cldmv/slothlet)