@cldmv/slothlet 2.11.0 → 3.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/AGENT-USAGE.md +355 -325
- package/README.md +554 -238
- package/dist/lib/builders/api-assignment.mjs +605 -0
- package/dist/lib/builders/api_builder.mjs +1073 -0
- package/dist/lib/builders/builder.mjs +94 -0
- package/dist/lib/builders/modes-processor.mjs +1816 -0
- package/dist/lib/errors.mjs +227 -0
- package/dist/lib/factories/component-base.mjs +96 -0
- package/dist/lib/factories/context.mjs +38 -0
- package/dist/lib/handlers/api-cache-manager.mjs +216 -0
- package/dist/lib/handlers/api-manager.mjs +2364 -0
- package/dist/lib/handlers/context-async.mjs +184 -0
- package/dist/lib/handlers/context-live.mjs +184 -0
- package/dist/lib/handlers/hook-manager.mjs +789 -0
- package/dist/lib/handlers/lifecycle-token.mjs +44 -0
- package/dist/lib/handlers/lifecycle.mjs +131 -0
- package/dist/lib/handlers/materialize-manager.mjs +64 -0
- package/dist/lib/handlers/metadata.mjs +500 -0
- package/dist/lib/handlers/ownership.mjs +338 -0
- package/dist/lib/handlers/unified-wrapper.mjs +3031 -0
- package/dist/lib/helpers/class-instance-wrapper.mjs +125 -0
- package/dist/lib/helpers/config.mjs +343 -0
- package/dist/lib/helpers/eventemitter-context.mjs +365 -0
- package/dist/lib/helpers/hint-detector.mjs +63 -0
- package/dist/lib/helpers/modes-utils.mjs +53 -0
- package/dist/lib/helpers/resolve-from-caller.mjs +123 -117
- package/dist/lib/helpers/sanitize.mjs +247 -168
- package/dist/lib/helpers/utilities.mjs +46 -81
- package/dist/lib/i18n/languages/de-de.json +377 -0
- package/dist/lib/i18n/languages/en-gb.json +377 -0
- package/dist/lib/i18n/languages/en-us.json +377 -0
- package/dist/lib/i18n/languages/es-mx.json +377 -0
- package/dist/lib/i18n/languages/fr-fr.json +377 -0
- package/dist/lib/i18n/languages/hi-in.json +377 -0
- package/dist/lib/i18n/languages/ja-jp.json +377 -0
- package/dist/lib/i18n/languages/ko-kr.json +377 -0
- package/dist/lib/i18n/languages/pt-br.json +377 -0
- package/dist/lib/i18n/languages/ru-ru.json +377 -0
- package/dist/lib/i18n/languages/zh-cn.json +377 -0
- package/dist/lib/i18n/translations.mjs +140 -0
- package/dist/lib/modes/eager.mjs +75 -0
- package/dist/lib/modes/lazy.mjs +97 -0
- package/dist/lib/processors/flatten.mjs +453 -0
- package/dist/lib/processors/loader.mjs +355 -0
- package/dist/lib/processors/type-generator.mjs +291 -0
- package/dist/lib/processors/typescript.mjs +188 -0
- package/dist/lib/runtime/runtime-asynclocalstorage.mjs +80 -522
- package/dist/lib/runtime/runtime-livebindings.mjs +45 -390
- package/dist/lib/runtime/runtime.mjs +39 -159
- package/dist/slothlet.mjs +525 -744
- package/docs/API-RULES.md +338 -486
- package/index.cjs +4 -4
- package/index.mjs +82 -45
- package/package.json +143 -30
- package/types/dist/lib/builders/api-assignment.d.mts +97 -0
- package/types/dist/lib/builders/api-assignment.d.mts.map +1 -0
- package/types/dist/lib/builders/api_builder.d.mts +96 -0
- package/types/dist/lib/builders/api_builder.d.mts.map +1 -0
- package/types/dist/lib/builders/builder.d.mts +60 -0
- package/types/dist/lib/builders/builder.d.mts.map +1 -0
- package/types/dist/lib/builders/modes-processor.d.mts +32 -0
- package/types/dist/lib/builders/modes-processor.d.mts.map +1 -0
- package/types/dist/lib/errors.d.mts +118 -0
- package/types/dist/lib/errors.d.mts.map +1 -0
- package/types/dist/lib/factories/component-base.d.mts +182 -0
- package/types/dist/lib/factories/component-base.d.mts.map +1 -0
- package/types/dist/lib/factories/context.d.mts +26 -0
- package/types/dist/lib/factories/context.d.mts.map +1 -0
- package/types/dist/lib/handlers/api-cache-manager.d.mts +208 -0
- package/types/dist/lib/handlers/api-cache-manager.d.mts.map +1 -0
- package/types/dist/lib/handlers/api-manager.d.mts +392 -0
- package/types/dist/lib/handlers/api-manager.d.mts.map +1 -0
- package/types/dist/lib/handlers/context-async.d.mts +66 -0
- package/types/dist/lib/handlers/context-async.d.mts.map +1 -0
- package/types/dist/lib/handlers/context-live.d.mts +65 -0
- package/types/dist/lib/handlers/context-live.d.mts.map +1 -0
- package/types/dist/lib/handlers/hook-manager.d.mts +199 -0
- package/types/dist/lib/handlers/hook-manager.d.mts.map +1 -0
- package/types/dist/lib/handlers/lifecycle-token.d.mts +49 -0
- package/types/dist/lib/handlers/lifecycle-token.d.mts.map +1 -0
- package/types/dist/lib/handlers/lifecycle.d.mts +90 -0
- package/types/dist/lib/handlers/lifecycle.d.mts.map +1 -0
- package/types/dist/lib/handlers/materialize-manager.d.mts +75 -0
- package/types/dist/lib/handlers/materialize-manager.d.mts.map +1 -0
- package/types/dist/lib/handlers/metadata.d.mts +215 -0
- package/types/dist/lib/handlers/metadata.d.mts.map +1 -0
- package/types/dist/lib/handlers/ownership.d.mts +170 -0
- package/types/dist/lib/handlers/ownership.d.mts.map +1 -0
- package/types/dist/lib/handlers/unified-wrapper.d.mts +250 -0
- package/types/dist/lib/handlers/unified-wrapper.d.mts.map +1 -0
- package/types/dist/lib/helpers/class-instance-wrapper.d.mts +54 -0
- package/types/dist/lib/helpers/class-instance-wrapper.d.mts.map +1 -0
- package/types/dist/lib/helpers/config.d.mts +96 -0
- package/types/dist/lib/helpers/config.d.mts.map +1 -0
- package/types/dist/lib/helpers/eventemitter-context.d.mts +31 -0
- package/types/dist/lib/helpers/eventemitter-context.d.mts.map +1 -0
- package/types/dist/lib/helpers/hint-detector.d.mts +20 -0
- package/types/dist/lib/helpers/hint-detector.d.mts.map +1 -0
- package/types/dist/lib/helpers/modes-utils.d.mts +35 -0
- package/types/dist/lib/helpers/modes-utils.d.mts.map +1 -0
- package/types/dist/lib/helpers/resolve-from-caller.d.mts +29 -145
- package/types/dist/lib/helpers/resolve-from-caller.d.mts.map +1 -1
- package/types/dist/lib/helpers/sanitize.d.mts +95 -94
- package/types/dist/lib/helpers/sanitize.d.mts.map +1 -1
- package/types/dist/lib/helpers/utilities.d.mts +53 -116
- package/types/dist/lib/helpers/utilities.d.mts.map +1 -1
- package/types/dist/lib/i18n/translations.d.mts +39 -0
- package/types/dist/lib/i18n/translations.d.mts.map +1 -0
- package/types/dist/lib/modes/eager.d.mts +36 -0
- package/types/dist/lib/modes/eager.d.mts.map +1 -0
- package/types/dist/lib/modes/lazy.d.mts +49 -0
- package/types/dist/lib/modes/lazy.d.mts.map +1 -0
- package/types/dist/lib/processors/flatten.d.mts +114 -0
- package/types/dist/lib/processors/flatten.d.mts.map +1 -0
- package/types/dist/lib/processors/loader.d.mts +47 -0
- package/types/dist/lib/processors/loader.d.mts.map +1 -0
- package/types/dist/lib/processors/type-generator.d.mts +19 -0
- package/types/dist/lib/processors/type-generator.d.mts.map +1 -0
- package/types/dist/lib/processors/typescript.d.mts +55 -0
- package/types/dist/lib/processors/typescript.d.mts.map +1 -0
- package/types/dist/lib/runtime/runtime-asynclocalstorage.d.mts +47 -42
- package/types/dist/lib/runtime/runtime-asynclocalstorage.d.mts.map +1 -1
- package/types/dist/lib/runtime/runtime-livebindings.d.mts +34 -65
- package/types/dist/lib/runtime/runtime-livebindings.d.mts.map +1 -1
- package/types/dist/lib/runtime/runtime.d.mts +39 -9
- package/types/dist/lib/runtime/runtime.d.mts.map +1 -1
- package/types/dist/slothlet.d.mts +184 -111
- package/types/dist/slothlet.d.mts.map +1 -1
- package/types/index.d.mts +1 -3
- package/dist/lib/engine/README.md +0 -21
- package/dist/lib/engine/slothlet_child.mjs +0 -59
- package/dist/lib/engine/slothlet_engine.mjs +0 -372
- package/dist/lib/engine/slothlet_esm.mjs +0 -230
- package/dist/lib/engine/slothlet_helpers.mjs +0 -455
- package/dist/lib/engine/slothlet_worker.mjs +0 -149
- package/dist/lib/helpers/als-eventemitter.mjs +0 -256
- package/dist/lib/helpers/api_builder/add_api.mjs +0 -553
- package/dist/lib/helpers/api_builder/analysis.mjs +0 -532
- package/dist/lib/helpers/api_builder/construction.mjs +0 -495
- package/dist/lib/helpers/api_builder/decisions.mjs +0 -748
- package/dist/lib/helpers/api_builder/metadata.mjs +0 -248
- package/dist/lib/helpers/api_builder.mjs +0 -41
- package/dist/lib/helpers/auto-wrap.mjs +0 -62
- package/dist/lib/helpers/hooks.mjs +0 -389
- package/dist/lib/helpers/instance-manager.mjs +0 -111
- package/dist/lib/helpers/metadata-api.mjs +0 -201
- package/dist/lib/helpers/multidefault.mjs +0 -216
- package/dist/lib/modes/slothlet_eager.mjs +0 -154
- package/dist/lib/modes/slothlet_lazy.mjs +0 -594
- package/docs/API-RULES-CONDITIONS.md +0 -712
- package/types/dist/lib/engine/slothlet_child.d.mts +0 -2
- package/types/dist/lib/engine/slothlet_child.d.mts.map +0 -1
- package/types/dist/lib/engine/slothlet_engine.d.mts +0 -31
- package/types/dist/lib/engine/slothlet_engine.d.mts.map +0 -1
- package/types/dist/lib/engine/slothlet_esm.d.mts +0 -19
- package/types/dist/lib/engine/slothlet_esm.d.mts.map +0 -1
- package/types/dist/lib/engine/slothlet_helpers.d.mts +0 -25
- package/types/dist/lib/engine/slothlet_helpers.d.mts.map +0 -1
- package/types/dist/lib/engine/slothlet_worker.d.mts +0 -2
- package/types/dist/lib/engine/slothlet_worker.d.mts.map +0 -1
- package/types/dist/lib/helpers/als-eventemitter.d.mts +0 -56
- package/types/dist/lib/helpers/als-eventemitter.d.mts.map +0 -1
- package/types/dist/lib/helpers/api_builder/add_api.d.mts +0 -102
- package/types/dist/lib/helpers/api_builder/add_api.d.mts.map +0 -1
- package/types/dist/lib/helpers/api_builder/analysis.d.mts +0 -189
- package/types/dist/lib/helpers/api_builder/analysis.d.mts.map +0 -1
- package/types/dist/lib/helpers/api_builder/construction.d.mts +0 -107
- package/types/dist/lib/helpers/api_builder/construction.d.mts.map +0 -1
- package/types/dist/lib/helpers/api_builder/decisions.d.mts +0 -213
- package/types/dist/lib/helpers/api_builder/decisions.d.mts.map +0 -1
- package/types/dist/lib/helpers/api_builder/metadata.d.mts +0 -99
- package/types/dist/lib/helpers/api_builder/metadata.d.mts.map +0 -1
- package/types/dist/lib/helpers/api_builder.d.mts +0 -6
- package/types/dist/lib/helpers/api_builder.d.mts.map +0 -1
- package/types/dist/lib/helpers/auto-wrap.d.mts +0 -49
- package/types/dist/lib/helpers/auto-wrap.d.mts.map +0 -1
- package/types/dist/lib/helpers/hooks.d.mts +0 -342
- package/types/dist/lib/helpers/hooks.d.mts.map +0 -1
- package/types/dist/lib/helpers/instance-manager.d.mts +0 -41
- package/types/dist/lib/helpers/instance-manager.d.mts.map +0 -1
- package/types/dist/lib/helpers/metadata-api.d.mts +0 -132
- package/types/dist/lib/helpers/metadata-api.d.mts.map +0 -1
- package/types/dist/lib/helpers/multidefault.d.mts +0 -90
- package/types/dist/lib/helpers/multidefault.d.mts.map +0 -1
- package/types/dist/lib/modes/slothlet_eager.d.mts +0 -65
- package/types/dist/lib/modes/slothlet_eager.d.mts.map +0 -1
- package/types/dist/lib/modes/slothlet_lazy.d.mts +0 -31
- package/types/dist/lib/modes/slothlet_lazy.d.mts.map +0 -1
- package/types/index.d.mts.map +0 -1
package/README.md
CHANGED
|
@@ -8,55 +8,72 @@
|
|
|
8
8
|
|
|
9
9
|
Choose your loading strategy based on your needs: **lazy mode** loads modules on-demand for faster startup and lower memory usage, while **eager mode** loads everything upfront for maximum runtime performance and predictable behavior.
|
|
10
10
|
|
|
11
|
-
With our **copy-left materialization** in lazy mode, you get the best of both worlds: the memory efficiency of on-demand loading with near-eager performance on repeated calls. Once a module is materialized, it stays materialized
|
|
11
|
+
With our **copy-left materialization** in lazy mode, you get the best of both worlds: the memory efficiency of on-demand loading with near-eager performance on repeated calls. Once a module is materialized, it stays materialized-no re-processing overhead.
|
|
12
12
|
|
|
13
13
|
The name might suggest we're taking it easy, but don't be fooled. **Slothlet delivers speed where it counts**, with smart optimizations that make your APIs fly.
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
**🎉 Welcome to the future of module loading with Slothlet v3!**
|
|
16
|
+
|
|
17
|
+
> _Where sophisticated architecture meets blazing performance - slothlet is anything but slow._
|
|
16
18
|
|
|
17
19
|
[![npm version]][npm_version_url] [![npm downloads]][npm_downloads_url] <!-- [![GitHub release]][github_release_url] -->[![GitHub downloads]][github_downloads_url] [![Last commit]][last_commit_url] <!-- [![Release date]][release_date_url] -->[![npm last update]][npm_last_update_url]
|
|
18
20
|
|
|
19
|
-
> [!NOTE]
|
|
21
|
+
> [!NOTE]
|
|
20
22
|
> **🚀 Production Ready Modes:**
|
|
21
23
|
>
|
|
22
24
|
> - **Eager Mode**: Fully stable and production-ready for immediate module loading
|
|
23
|
-
> - **Lazy Mode**: Production-ready with advanced copy-left materialization and
|
|
24
|
-
|
|
25
|
-
> [!CAUTION]
|
|
26
|
-
> **⚙️ Experimental Modes:**
|
|
27
|
-
>
|
|
28
|
-
> - **Worker, Fork, Child, VM modes**: In active development, not recommended for production use
|
|
29
|
-
>
|
|
30
|
-
> Please report issues and contribute feedback to help improve the experimental features.
|
|
25
|
+
> - **Lazy Mode**: Production-ready with advanced copy-left materialization and 2.2x faster startup (function calls within 6% of eager - essentially equal)
|
|
31
26
|
|
|
32
27
|
[![Contributors]][contributors_url] [![Sponsor shinrai]][sponsor_url]
|
|
33
28
|
|
|
34
29
|
---
|
|
35
30
|
|
|
31
|
+
## 🎉 Introducing Slothlet v3.0
|
|
32
|
+
|
|
33
|
+
> [!IMPORTANT]
|
|
34
|
+
> **Slothlet v3.0 is a major release - the biggest since v2.0.**
|
|
35
|
+
|
|
36
|
+
v3 rebuilds Slothlet from the inside out with a **Unified Wrapper architecture** that delivers consistent, inspectable, hook-intercepted API proxies across every loading mode. On top of this foundation comes a redesigned hook system with three-phase subset ordering, per-request context isolation improvements, a full internationalization layer, background materialization with progress tracking, granular API mutation controls, collision modes for runtime API management, and lifecycle events for every stage of the module lifecycle.
|
|
37
|
+
|
|
38
|
+
Every feature has been hardened with a comprehensive test suite - over **5,300 tests** across eager, lazy, CJS, ESM, TypeScript, and mixed module scenarios.
|
|
39
|
+
|
|
40
|
+
### What's New in v3.0
|
|
41
|
+
|
|
42
|
+
- 🏗️ **Unified Wrapper** - single consistent proxy layer for all modes; `console.log(api.math)` now shows real contents
|
|
43
|
+
- 🎣 **Redesigned Hook System** - new `hook:` config key, `api.slothlet.hook.*` access path, three-phase subset ordering (`before → primary → after`)
|
|
44
|
+
- 🌍 **Full i18n** - all error and debug messages are translated and available in 9 languages: English, Spanish, French, German, Portuguese, Italian, Japanese, Chinese (Simplified), and Korean
|
|
45
|
+
- 💤 **Background Materialization** - `backgroundMaterialize: true` pre-loads lazy modules without blocking; `api.slothlet.materialize.wait()` to await completion
|
|
46
|
+
- ⚡ **Lifecycle Events** - subscribe to `impl:created`, `impl:changed`, `impl:removed`, and `materialized:complete` via `api.slothlet.lifecycle.on/off()`
|
|
47
|
+
- 🔀 **Collision Modes** - replace `allowApiOverwrite` with typed modes: `merge`, `skip`, `overwrite`, `throw` - independently configurable for initial load vs runtime `add()`
|
|
48
|
+
- 🔒 **Mutation Controls** - granular per-operation enable/disable for `add`, `remove`, and `reload`
|
|
49
|
+
- 🧹 **Sanitization Improvements** - runtime `api.slothlet.sanitize()` method; helper export renamed to `sanitizePropertyName`
|
|
50
|
+
- 🔄 **Improved Context Isolation** - `.run()` and `.scope()` use a child-instance model; full isolation between Slothlet instances
|
|
51
|
+
|
|
52
|
+
📋 **[See the full v3.0 changelog](./docs/changelog/v3.0.md)**
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
36
56
|
## ✨ What's New
|
|
37
57
|
|
|
38
|
-
### Latest:
|
|
58
|
+
### Latest: v3.0.0 (February 2026)
|
|
39
59
|
|
|
40
|
-
- **
|
|
41
|
-
- **
|
|
42
|
-
- **
|
|
43
|
-
- **
|
|
44
|
-
- **
|
|
45
|
-
-
|
|
60
|
+
- **Unified Wrapper Architecture** - consistent proxy surface for all modes and operations
|
|
61
|
+
- **Hook System Redesigned** - `hook:` config key, `api.slothlet.hook.*`, three-phase subset ordering
|
|
62
|
+
- **Full i18n Support** - 9 languages for all error and debug messages
|
|
63
|
+
- **Background Materialization** - pre-load lazy modules without blocking startup
|
|
64
|
+
- **Lifecycle Event System** - `api.slothlet.lifecycle.on/off()` for module lifecycle events
|
|
65
|
+
- **Collision Modes** - fine-grained control over API namespace conflicts
|
|
66
|
+
- **Mutation Controls** - per-operation access restrictions for API mutations
|
|
67
|
+
- [View full v3.0 Changelog](./docs/changelog/v3.0.md)
|
|
46
68
|
|
|
47
69
|
### Recent Releases
|
|
48
70
|
|
|
71
|
+
- **v2.11.0** - AddApi Special File Pattern (Rule 11), smart flattening enhancements ([Changelog](https://github.com/CLDMV/slothlet/blob/master/docs/changelog/v2.11.md))
|
|
49
72
|
- **v2.10.0** - Function metadata tagging and introspection capabilities ([Changelog](https://github.com/CLDMV/slothlet/blob/master/docs/changelog/v2.10.md))
|
|
50
|
-
- **v2.9** - Per-Request Context Isolation
|
|
51
|
-
- **v2.
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
- **v2.5** - Architectural consolidation and API consistency ([Changelog](https://github.com/CLDMV/slothlet/blob/master/docs/changelog/v2.5.md))
|
|
55
|
-
- **v2.4** - Multi-default export handling ([Changelog](https://github.com/CLDMV/slothlet/blob/master/docs/changelog/v2.4.md))
|
|
56
|
-
- **v2.3** - EventEmitter & Class Context Propagation ([Changelog](https://github.com/CLDMV/slothlet/blob/master/docs/changelog/v2.3.md))
|
|
57
|
-
- **v2.2** - Case preservation options ([Changelog](https://github.com/CLDMV/slothlet/blob/master/docs/changelog/v2.2.md))
|
|
58
|
-
- **v2.1** - Advanced sanitization patterns ([Changelog](https://github.com/CLDMV/slothlet/blob/master/docs/changelog/v2.1.md))
|
|
59
|
-
- **v2.0** - Complete Architectural Rewrite ([Changelog](https://github.com/CLDMV/slothlet/blob/master/docs/changelog/v2.0.md))
|
|
73
|
+
- **v2.9** - Per-Request Context Isolation ([Changelog](https://github.com/CLDMV/slothlet/blob/master/docs/changelog/v2.9.md))
|
|
74
|
+
- **v2.7** - Hook system introduced ([Changelog](https://github.com/CLDMV/slothlet/blob/master/docs/changelog/v2.7.md))
|
|
75
|
+
|
|
76
|
+
📚 **For complete version history and detailed release notes, see [docs/changelog/](./docs/changelog/) folder.**
|
|
60
77
|
|
|
61
78
|
---
|
|
62
79
|
|
|
@@ -65,9 +82,9 @@ The name might suggest we're taking it easy, but don't be fooled. **Slothlet del
|
|
|
65
82
|
### 🎯 **Dual Loading Strategies**
|
|
66
83
|
|
|
67
84
|
- **Eager Loading**: Immediate loading for maximum performance in production environments
|
|
68
|
-
- **Lazy Loading**: Copy-left materialization with look-ahead proxies (
|
|
85
|
+
- **Lazy Loading**: Copy-left materialization with look-ahead proxies (2.2x faster startup, function calls equal to eager after materialization)
|
|
69
86
|
|
|
70
|
-
> [!IMPORTANT]
|
|
87
|
+
> [!IMPORTANT]
|
|
71
88
|
> **Function Call Patterns:**
|
|
72
89
|
>
|
|
73
90
|
> - **Lazy Mode**: ALL function calls must be awaited (`await api.math.add(2, 3)`) due to materialization process
|
|
@@ -75,30 +92,44 @@ The name might suggest we're taking it easy, but don't be fooled. **Slothlet del
|
|
|
75
92
|
|
|
76
93
|
### ⚡ Performance Excellence
|
|
77
94
|
|
|
78
|
-
- **2.
|
|
79
|
-
- **
|
|
80
|
-
- **Copy-left materialization**: Once loaded, modules stay materialized
|
|
95
|
+
- **Startup Performance**: 2.2x faster startup in lazy mode (15.41ms vs 34.28ms)
|
|
96
|
+
- **Runtime Performance**: Function calls essentially equal between modes (9.99μs lazy vs 9.46μs eager - within 6% measurement noise)
|
|
97
|
+
- **Copy-left materialization**: Once loaded, modules stay materialized - no re-processing overhead
|
|
81
98
|
- **Zero dependencies**: Pure Node.js implementation
|
|
99
|
+
- **Memory efficiency**: Lazy mode loads modules on-demand, eager mode optimizes for predictable behavior
|
|
100
|
+
|
|
101
|
+
**Mode Selection Guide:**
|
|
102
|
+
|
|
103
|
+
- **Eager Mode**: Best for production environments with maximum runtime performance and predictable behavior
|
|
104
|
+
- **Lazy Mode**: Best for development and applications with large APIs where startup time matters
|
|
82
105
|
|
|
83
|
-
📊 **For comprehensive performance
|
|
106
|
+
📊 **For comprehensive performance benchmarks and analysis, see [docs/PERFORMANCE.md](https://github.com/CLDMV/slothlet/blob/master/docs/PERFORMANCE.md)**
|
|
84
107
|
|
|
85
|
-
### 🎣 **Hook System**
|
|
108
|
+
### 🎣 **Hook System** _(redesigned in v3)_
|
|
86
109
|
|
|
87
|
-
Powerful function interceptor system with 4 hook types:
|
|
110
|
+
Powerful function interceptor system with 4 hook types and three-phase subset ordering:
|
|
88
111
|
|
|
89
|
-
- **`before`** - Modify arguments or cancel execution
|
|
112
|
+
- **`before`** - Modify arguments or cancel execution (**must be synchronous**)
|
|
90
113
|
- **`after`** - Transform return values
|
|
91
|
-
- **`always`** - Observe final results (read-only)
|
|
114
|
+
- **`always`** - Observe final results (read-only; fires even on short-circuit)
|
|
92
115
|
- **`error`** - Monitor and handle errors with detailed source tracking
|
|
93
116
|
|
|
94
|
-
Pattern matching, priority control, runtime enable/disable, and short-circuit support included.
|
|
117
|
+
Each hook type supports three ordered execution **subsets**: `"before"` → `"primary"` (default) → `"after"`. Pattern matching, priority control, runtime enable/disable, and short-circuit support included.
|
|
95
118
|
|
|
96
119
|
🎣 **For complete hook system documentation, see [docs/HOOKS.md](https://github.com/CLDMV/slothlet/blob/master/docs/HOOKS.md)**
|
|
97
120
|
|
|
121
|
+
### 🌍 **Full Internationalization** _(new in v3)_
|
|
122
|
+
|
|
123
|
+
All error messages and debug output are translated. Supported languages:
|
|
124
|
+
English · Spanish · French · German · Portuguese · Italian · Japanese · Chinese (Simplified) · Korean
|
|
125
|
+
|
|
126
|
+
Configure via `i18n: { language: "es" }` in your slothlet config.
|
|
127
|
+
|
|
98
128
|
### 🔄 **Context Propagation**
|
|
99
129
|
|
|
100
130
|
Automatic context preservation across all asynchronous boundaries:
|
|
101
131
|
|
|
132
|
+
- **Per-request isolation**: `api.slothlet.context.run(ctx, fn)` and `api.slothlet.context.scope(ctx)`
|
|
102
133
|
- **EventEmitter propagation**: Context maintained across all event callbacks
|
|
103
134
|
- **Class instance propagation**: Context preserved in class method calls
|
|
104
135
|
- **Zero configuration**: Works automatically with TCP servers, HTTP servers, and custom EventEmitters
|
|
@@ -109,16 +140,16 @@ Automatic context preservation across all asynchronous boundaries:
|
|
|
109
140
|
|
|
110
141
|
- **Intelligent Flattening**: Clean APIs with automatic structure optimization (`math/math.mjs` → `api.math`)
|
|
111
142
|
- **Smart Naming**: Preserves original capitalization (`auto-ip.mjs` with `autoIP` → `api.autoIP`)
|
|
112
|
-
- **Advanced Sanitization**: Custom naming rules with glob and boundary patterns
|
|
143
|
+
- **Advanced Sanitization**: Custom naming rules with glob and boundary patterns; `api.slothlet.sanitize()` at runtime
|
|
113
144
|
- **Hybrid Exports**: Support for callable APIs with methods, default + named exports
|
|
114
145
|
|
|
115
|
-
🏗️ **For module structure examples, see [docs/MODULE-STRUCTURE.md](https://github.com/CLDMV/slothlet/blob/master/docs/MODULE-STRUCTURE.md)**
|
|
116
|
-
📐 **For API flattening rules, see [docs/API-FLATTENING.md](https://github.com/CLDMV/slothlet/blob/master/docs/API-FLATTENING.md)**
|
|
146
|
+
🏗️ **For module structure examples, see [docs/MODULE-STRUCTURE.md](https://github.com/CLDMV/slothlet/blob/master/docs/MODULE-STRUCTURE.md)**
|
|
147
|
+
📐 **For API flattening rules, see [docs/API-RULES/API-FLATTENING.md](https://github.com/CLDMV/slothlet/blob/master/docs/API-RULES/API-FLATTENING.md)**
|
|
117
148
|
|
|
118
|
-
### 🔗 **
|
|
149
|
+
### 🔗 **Runtime & Context System**
|
|
119
150
|
|
|
120
|
-
- **
|
|
121
|
-
- **
|
|
151
|
+
- **Context Isolation**: Automatic per-request isolation using AsyncLocalStorage (default); switchable to live-bindings mode via `runtime: "live"` config option
|
|
152
|
+
- **Cross-Module Access**: `self` and `context` always available inside API modules via `@cldmv/slothlet/runtime`
|
|
122
153
|
- **Mixed Module Support**: Seamlessly blend ESM and CommonJS modules
|
|
123
154
|
- **Copy-Left Preservation**: Materialized functions stay materialized
|
|
124
155
|
|
|
@@ -127,6 +158,7 @@ Automatic context preservation across all asynchronous boundaries:
|
|
|
127
158
|
- **TypeScript-Friendly**: Comprehensive JSDoc annotations with auto-generated declarations
|
|
128
159
|
- **Configurable Debug**: Detailed logging via CLI flags or environment variables
|
|
129
160
|
- **Multiple Instances**: Parameter-based isolation for complex applications
|
|
161
|
+
- **Inspectable APIs**: `console.log(api.math)` now shows real module contents (v3+)
|
|
130
162
|
- **Development Checks**: Built-in environment detection with silent production behavior
|
|
131
163
|
|
|
132
164
|
---
|
|
@@ -136,7 +168,7 @@ Automatic context preservation across all asynchronous boundaries:
|
|
|
136
168
|
### Requirements
|
|
137
169
|
|
|
138
170
|
- **Node.js v16.20.2 or higher** (required for stack trace API fixes used in path resolution)
|
|
139
|
-
- Node.js 16.4
|
|
171
|
+
- Node.js 16.4–16.19 has a stack trace regression. For these versions, use slothlet 2.10.0: `npm install @cldmv/slothlet@2.10.0`
|
|
140
172
|
|
|
141
173
|
### Install
|
|
142
174
|
|
|
@@ -173,7 +205,6 @@ const cjsResult = api.mathCjs.divide(10, 2);
|
|
|
173
205
|
```javascript
|
|
174
206
|
const slothlet = require("@cldmv/slothlet");
|
|
175
207
|
|
|
176
|
-
// Same usage pattern works with CommonJS
|
|
177
208
|
const api = await slothlet({
|
|
178
209
|
dir: "./api",
|
|
179
210
|
context: { env: "production" }
|
|
@@ -190,7 +221,7 @@ import slothlet from "@cldmv/slothlet";
|
|
|
190
221
|
|
|
191
222
|
// Lazy mode with copy-left materialization
|
|
192
223
|
const api = await slothlet({
|
|
193
|
-
mode: "lazy",
|
|
224
|
+
mode: "lazy",
|
|
194
225
|
dir: "./api",
|
|
195
226
|
apiDepth: 3
|
|
196
227
|
});
|
|
@@ -202,152 +233,104 @@ const result1 = await api.math.add(2, 3);
|
|
|
202
233
|
const result2 = await api.math.add(5, 7);
|
|
203
234
|
```
|
|
204
235
|
|
|
205
|
-
### Hook System Example
|
|
236
|
+
### Hook System Example _(v3 API)_
|
|
206
237
|
|
|
207
238
|
```javascript
|
|
208
239
|
import slothlet from "@cldmv/slothlet";
|
|
209
240
|
|
|
210
241
|
const api = await slothlet({
|
|
211
242
|
dir: "./api",
|
|
212
|
-
|
|
243
|
+
hook: true // Enable hooks - note: "hook" singular (v3)
|
|
213
244
|
});
|
|
214
245
|
|
|
215
246
|
// Before hook: Modify arguments
|
|
216
|
-
api.
|
|
217
|
-
"
|
|
218
|
-
"before",
|
|
247
|
+
api.slothlet.hook.on(
|
|
248
|
+
"before:math.add",
|
|
219
249
|
({ path, args }) => {
|
|
220
250
|
console.log(`Calling ${path} with args:`, args);
|
|
221
|
-
return [args[0] * 2, args[1] * 2];
|
|
251
|
+
return [args[0] * 2, args[1] * 2]; // Return array to replace arguments
|
|
222
252
|
},
|
|
223
|
-
{
|
|
253
|
+
{ id: "double-args", priority: 100 }
|
|
224
254
|
);
|
|
225
255
|
|
|
226
256
|
// After hook: Transform result
|
|
227
|
-
api.
|
|
228
|
-
"
|
|
229
|
-
"after",
|
|
257
|
+
api.slothlet.hook.on(
|
|
258
|
+
"after:math.*",
|
|
230
259
|
({ path, result }) => {
|
|
231
260
|
console.log(`${path} returned:`, result);
|
|
232
261
|
return result * 10;
|
|
233
262
|
},
|
|
234
|
-
{
|
|
263
|
+
{ id: "scale-result" }
|
|
235
264
|
);
|
|
236
265
|
|
|
237
|
-
// Always hook: Observe final result
|
|
238
|
-
api.
|
|
239
|
-
"
|
|
240
|
-
"always",
|
|
266
|
+
// Always hook: Observe final result (read-only)
|
|
267
|
+
api.slothlet.hook.on(
|
|
268
|
+
"always:**",
|
|
241
269
|
({ path, result, hasError }) => {
|
|
242
270
|
console.log(hasError ? `${path} failed` : `${path} succeeded`);
|
|
243
271
|
},
|
|
244
|
-
{
|
|
272
|
+
{ id: "logger" }
|
|
245
273
|
);
|
|
246
274
|
|
|
247
275
|
// Error hook: Monitor errors with source tracking
|
|
248
|
-
api.
|
|
249
|
-
"error
|
|
250
|
-
"error",
|
|
276
|
+
api.slothlet.hook.on(
|
|
277
|
+
"error:**",
|
|
251
278
|
({ path, error, source }) => {
|
|
252
279
|
console.error(`Error in ${path}:`, error.message);
|
|
253
|
-
console.error(`Source: ${source.type}`); // 'before'
|
|
280
|
+
console.error(`Source: ${source.type}`); // 'before' | 'after' | 'function' | 'always'
|
|
254
281
|
},
|
|
255
|
-
{
|
|
282
|
+
{ id: "error-monitor" }
|
|
256
283
|
);
|
|
257
284
|
|
|
258
285
|
// Call function - hooks execute automatically
|
|
259
286
|
const result = await api.math.add(2, 3);
|
|
260
287
|
```
|
|
261
288
|
|
|
262
|
-
### Dynamic API Extension
|
|
263
|
-
|
|
264
|
-
Load additional modules at runtime and extend your API dynamically:
|
|
289
|
+
### Dynamic API Extension _(v3 API)_
|
|
265
290
|
|
|
266
291
|
```javascript
|
|
267
292
|
import slothlet from "@cldmv/slothlet";
|
|
268
293
|
|
|
269
294
|
const api = await slothlet({ dir: "./api" });
|
|
270
295
|
|
|
271
|
-
// Add
|
|
272
|
-
await api.
|
|
296
|
+
// Add modules at runtime
|
|
297
|
+
await api.slothlet.api.add("plugins", "./plugins-folder");
|
|
273
298
|
api.plugins.myPlugin();
|
|
274
299
|
|
|
275
300
|
// Create nested API structures
|
|
276
|
-
await api.
|
|
301
|
+
await api.slothlet.api.add("runtime.plugins", "./more-plugins");
|
|
277
302
|
api.runtime.plugins.loader();
|
|
278
303
|
|
|
279
304
|
// Add with metadata for security/authorization
|
|
280
|
-
await api.
|
|
305
|
+
await api.slothlet.api.add("plugins.trusted", "./trusted-plugins", {
|
|
281
306
|
trusted: true,
|
|
282
|
-
permissions: ["read", "write", "admin"]
|
|
283
|
-
version: "1.0.0"
|
|
284
|
-
});
|
|
285
|
-
|
|
286
|
-
await api.addApi("plugins.external", "./third-party", {
|
|
287
|
-
trusted: false,
|
|
288
|
-
permissions: ["read"]
|
|
307
|
+
permissions: ["read", "write", "admin"]
|
|
289
308
|
});
|
|
290
309
|
|
|
291
|
-
//
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
console.log(meta.permissions); // ["read", "write", "admin"]
|
|
310
|
+
// Remove and reload
|
|
311
|
+
await api.slothlet.api.remove("oldModule");
|
|
312
|
+
await api.slothlet.api.reload("database.*");
|
|
295
313
|
```
|
|
296
314
|
|
|
297
|
-
**Security & Authorization with metadataAPI:**
|
|
298
|
-
|
|
299
|
-
```javascript
|
|
300
|
-
// Inside your modules, use metadataAPI for runtime introspection
|
|
301
|
-
import { metadataAPI } from "@cldmv/slothlet/runtime";
|
|
302
|
-
|
|
303
|
-
export async function sensitiveOperation() {
|
|
304
|
-
// Check caller's metadata
|
|
305
|
-
const caller = await metadataAPI.caller();
|
|
306
|
-
|
|
307
|
-
if (!caller?.trusted) {
|
|
308
|
-
throw new Error("Unauthorized: Caller is not trusted");
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
if (!caller.permissions.includes("admin")) {
|
|
312
|
-
throw new Error("Unauthorized: Admin permission required");
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
// Proceed with secure operation
|
|
316
|
-
return "Success";
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
// Get metadata by path
|
|
320
|
-
const meta = await metadataAPI.get("plugins.trusted.someFunc");
|
|
321
|
-
|
|
322
|
-
// Get current function's metadata
|
|
323
|
-
const self = await metadataAPI.self();
|
|
324
|
-
console.log("My version:", self.version);
|
|
325
|
-
```
|
|
326
|
-
|
|
327
|
-
🔒 **For complete metadata system documentation, see [docs/METADATA.md](https://github.com/CLDMV/slothlet/blob/master/docs/METADATA.md)**
|
|
328
|
-
|
|
329
315
|
---
|
|
330
316
|
|
|
331
317
|
## 📚 Configuration Options
|
|
332
318
|
|
|
333
|
-
| Option
|
|
334
|
-
|
|
|
335
|
-
| `dir`
|
|
336
|
-
| `mode`
|
|
337
|
-
| `
|
|
338
|
-
| `
|
|
339
|
-
| `
|
|
340
|
-
| `
|
|
341
|
-
| `
|
|
342
|
-
| `
|
|
343
|
-
| `
|
|
344
|
-
| `
|
|
345
|
-
| `
|
|
346
|
-
| `
|
|
347
|
-
| `
|
|
348
|
-
| `hooks` | `mixed` | `false` | Enable hook system: `true` (enable all), `"pattern"` (enable with pattern), or object with `enabled`, `pattern`, `suppressErrors` options |
|
|
349
|
-
|
|
350
|
-
**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)**
|
|
319
|
+
| Option | Type | Default | Description |
|
|
320
|
+
| ------------------------- | --------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
321
|
+
| `dir` | `string` | `"api"` | Directory to load API modules from (absolute or relative path) |
|
|
322
|
+
| `mode` | `string` | `"eager"` | Loading mode - `"lazy"` for on-demand loading, `"eager"` for immediate loading |
|
|
323
|
+
| `runtime` | `string` | `"async"` | Runtime binding system: `"async"` for AsyncLocalStorage (default), `"live"` for live-bindings |
|
|
324
|
+
| `apiDepth` | `number` | `Infinity` | Directory traversal depth - `0` for root only, `Infinity` for all levels |
|
|
325
|
+
| `debug` | `boolean` | `false` | Enable verbose logging (also via `--slothletdebug` flag or `SLOTHLET_DEBUG=true` env var) |
|
|
326
|
+
| `context` | `object` | `{}` | Context data injected into live-binding (available via `import { context } from "@cldmv/slothlet/runtime"`) |
|
|
327
|
+
| `reference` | `object` | `{}` | Reference object merged into API root level |
|
|
328
|
+
| `sanitize` | `object` | `{}` | Advanced filename-to-API transformation control with `lowerFirst`, `preserveAllUpper`, `preserveAllLower`, and `rules` (supports exact matches, glob patterns `*json*`, and boundary patterns `**url**`) |
|
|
329
|
+
| `hook` | `mixed` | `false` | Enable hook system: `true` (enable all), `"pattern"` (enable with pattern), or object with `enabled`, `pattern`, `suppressErrors` options - **note: `hook` singular, not `hooks`** |
|
|
330
|
+
| `backgroundMaterialize` | `boolean` | `false` | In lazy mode: start background pre-loading of all modules immediately after init; automatically enables materialization tracking and the `materialized:complete` lifecycle event |
|
|
331
|
+
| `api.collision` | `mixed` | `"merge"` | Collision mode for API namespace conflicts: `"merge"`, `"skip"`, `"overwrite"`, `"throw"` - or `{ initial: "merge", api: "skip" }` to set independently for load vs runtime `add()` |
|
|
332
|
+
| `api.mutations` | `object` | all `true` | Per-operation mutation controls: `{ add: true, remove: true, reload: true }` - set any to `false` to disable |
|
|
333
|
+
| `i18n` | `object` | `{}` | Internationalization settings: `{ language: "en" }` - supported: `en`, `es`, `fr`, `de`, `pt`, `it`, `ja`, `zh`, `ko` |
|
|
351
334
|
|
|
352
335
|
---
|
|
353
336
|
|
|
@@ -394,9 +377,9 @@ flowchart TD
|
|
|
394
377
|
direction TB
|
|
395
378
|
LAZYCALL0 --> LAZYCALL2
|
|
396
379
|
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
380
|
+
LAZYCALL0@{ shape: rounded, label: "📞 First call" }
|
|
381
|
+
LAZYCALL1@{ shape: rounded, label: "🔁 Sequential calls" }
|
|
382
|
+
LAZYCALL2@{ shape: rounded, label: "🧩 Materialize" }
|
|
400
383
|
end
|
|
401
384
|
|
|
402
385
|
EAGER --> READYTOUSE
|
|
@@ -410,24 +393,23 @@ flowchart TD
|
|
|
410
393
|
LAZYCALL1 --> MATERIALIZEDFUNCTION
|
|
411
394
|
LAZYCALL2 --> MATERIALIZEDFUNCTION
|
|
412
395
|
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
396
|
+
READYTOUSE@{ shape: rounded, label: "🎯 Ready to Use" }
|
|
397
|
+
MATERIALIZEDFUNCTION@{ shape: rounded, label: "✅ Materialized method/property" }
|
|
398
|
+
CALL@{ shape: trap-b, label: "📞 Call" }
|
|
416
399
|
|
|
417
|
-
%% Notes as unattached nodes with braces shape
|
|
418
400
|
subgraph ALWAYS ["✨ Extras Always On"]
|
|
419
401
|
direction TB
|
|
420
402
|
ALWAYS0 ~~~ ALWAYS1
|
|
421
403
|
ALWAYS1 ~~~ ALWAYS2
|
|
422
404
|
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
405
|
+
ALWAYS0@{ shape: rounded, label: "🔗 Live Bindings ALS<br/>Per-instance context isolation" }
|
|
406
|
+
ALWAYS1@{ shape: rounded, label: "🏷️ Smart Naming & Flattening<br/>Multiple rules for clean APIs" }
|
|
407
|
+
ALWAYS2@{ shape: rounded, label: "🔄 Mixed Module Support<br/>Seamlessly mix .mjs and .cjs" }
|
|
426
408
|
end
|
|
427
409
|
|
|
428
410
|
MODULEFOLDERS@{ shape: st-rect, label: "📁 Modules Folder<br/>.mjs and/or .cjs files<br/>math.mjs, string.cjs, async.mjs" }
|
|
429
|
-
|
|
430
|
-
|
|
411
|
+
SLOTHLET@{ shape: rounded, label: "🔧 Call slothlet(options)" }
|
|
412
|
+
CHOOSEMODE@{ shape: diamond, label: "Choose Mode<br/>in options" }
|
|
431
413
|
|
|
432
414
|
style EAGER0 stroke:#9BC66B,color:#9BC66B,opacity:0.5
|
|
433
415
|
style EAGER1 stroke:#9BC66B,color:#9BC66B,opacity:0.5
|
|
@@ -441,7 +423,6 @@ flowchart TD
|
|
|
441
423
|
style LAZY4 stroke:#9BC66B,color:#9BC66B,opacity:0.5
|
|
442
424
|
style LAZY5 stroke:#9BC66B,color:#9BC66B,opacity:0.5
|
|
443
425
|
|
|
444
|
-
%% Slothlet brand colors - #9BC66B primary on dark theme
|
|
445
426
|
style MODULEFOLDERS fill:#1a1a1a,stroke:#9BC66B,stroke-width:2px,color:#9BC66B,opacity:0.5
|
|
446
427
|
style SLOTHLET fill:#1a1a1a,stroke:#9BC66B,stroke-width:2px,color:#9BC66B,opacity:0.5
|
|
447
428
|
style CHOOSEMODE fill:#1a1a1a,stroke:#9BC66B,stroke-width:2px,color:#9BC66B,opacity:0.5
|
|
@@ -449,24 +430,20 @@ flowchart TD
|
|
|
449
430
|
style CALL fill:#1a1a1a,stroke:#9BC66B,stroke-width:2px,color:#9BC66B,opacity:0.5
|
|
450
431
|
style MATERIALIZEDFUNCTION fill:#1a1a1a,stroke:#9BC66B,stroke-width:2px,color:#9BC66B,opacity:0.5
|
|
451
432
|
|
|
452
|
-
%% Eager mode - primary green
|
|
453
433
|
style EAGER fill:#0d1a0d,stroke:#9BC66B,stroke-width:3px,color:#9BC66B,opacity:0.5
|
|
454
434
|
style EAGERCALL fill:#0d1a0d,stroke:#9BC66B,stroke-width:2px,color:#9BC66B,opacity:0.5
|
|
455
435
|
|
|
456
|
-
%% Lazy mode - lighter green tint
|
|
457
436
|
style LAZY fill:#0d1a0d,stroke:#B8D982,stroke-width:3px,color:#B8D982,opacity:0.5
|
|
458
437
|
style LAZYCALL fill:#0d1a0d,stroke:#B8D982,stroke-width:2px,color:#B8D982,opacity:0.5
|
|
459
438
|
style LAZYCALL0 fill:#1a1a1a,stroke:#B8D982,stroke-width:2px,color:#B8D982,opacity:0.5
|
|
460
439
|
style LAZYCALL1 fill:#1a1a1a,stroke:#B8D982,stroke-width:2px,color:#B8D982,opacity:0.5
|
|
461
440
|
style LAZYCALL2 fill:#1a1a1a,stroke:#B8D982,stroke-width:2px,color:#B8D982,opacity:0.5
|
|
462
441
|
|
|
463
|
-
%% Always available - accent green
|
|
464
442
|
style ALWAYS fill:#0d1a0d,stroke:#7FA94F,stroke-width:3px,color:#7FA94F,opacity:0.5
|
|
465
443
|
style ALWAYS0 fill:#1a1a1a,stroke:#7FA94F,stroke-width:1px,color:#7FA94F,opacity:0.5
|
|
466
444
|
style ALWAYS1 fill:#1a1a1a,stroke:#7FA94F,stroke-width:1px,color:#7FA94F,opacity:0.5
|
|
467
445
|
style ALWAYS2 fill:#1a1a1a,stroke:#7FA94F,stroke-width:1px,color:#7FA94F,opacity:0.5
|
|
468
446
|
|
|
469
|
-
%% Arrow styling
|
|
470
447
|
linkStyle default stroke:#9BC66B,stroke-width:3px,opacity:0.5
|
|
471
448
|
linkStyle 4,5,6,7,8,18,19 stroke-width:0px
|
|
472
449
|
```
|
|
@@ -480,7 +457,7 @@ flowchart TD
|
|
|
480
457
|
**Best for:** Production environments, maximum runtime performance, predictable behavior
|
|
481
458
|
|
|
482
459
|
```javascript
|
|
483
|
-
const api = await slothlet({ dir: "./api" }); //
|
|
460
|
+
const api = await slothlet({ dir: "./api" }); // mode: "eager" by default
|
|
484
461
|
|
|
485
462
|
// Functions behave as originally defined
|
|
486
463
|
const result = api.math.add(2, 3); // Sync - no await needed
|
|
@@ -489,7 +466,7 @@ const asyncResult = await api.async.processData({ data: "test" }); // Async need
|
|
|
489
466
|
|
|
490
467
|
**Benefits:**
|
|
491
468
|
|
|
492
|
-
- ✅
|
|
469
|
+
- ✅ Fast function calls (9.46μs average - within 6% of lazy mode)
|
|
493
470
|
- ✅ Predictable performance (no materialization delays)
|
|
494
471
|
- ✅ Functions behave exactly as originally defined
|
|
495
472
|
|
|
@@ -501,24 +478,414 @@ const asyncResult = await api.async.processData({ data: "test" }); // Async need
|
|
|
501
478
|
const api = await slothlet({ mode: "lazy", dir: "./api" });
|
|
502
479
|
|
|
503
480
|
// ALL calls must be awaited (materialization process)
|
|
504
|
-
const result1 = await api.math.add(2, 3); // First: ~
|
|
505
|
-
const result2 = await api.math.add(5, 7); // Subsequent:
|
|
481
|
+
const result1 = await api.math.add(2, 3); // First: ~538μs avg (materialization)
|
|
482
|
+
const result2 = await api.math.add(5, 7); // Subsequent: ~10μs (materialized)
|
|
506
483
|
```
|
|
507
484
|
|
|
508
485
|
**Benefits:**
|
|
509
486
|
|
|
510
|
-
- ✅ 2.
|
|
511
|
-
- ✅
|
|
487
|
+
- ✅ 2.2x faster startup (15.41ms vs 34.28ms)
|
|
488
|
+
- ✅ Equal function call performance (9.99μs vs 9.46μs eager - within 6% measurement noise)
|
|
512
489
|
- ✅ Memory efficient (loads only what you use)
|
|
513
490
|
- ✅ Copy-left optimization (once loaded, stays loaded)
|
|
514
491
|
|
|
515
|
-
|
|
492
|
+
### Lazy Mode with Background Materialization _(new in v3)_
|
|
493
|
+
|
|
494
|
+
**Best for:** Lazy startup performance with eager runtime performance - pre-warm everything in the background
|
|
495
|
+
|
|
496
|
+
```javascript
|
|
497
|
+
const api = await slothlet({
|
|
498
|
+
mode: "lazy",
|
|
499
|
+
dir: "./api",
|
|
500
|
+
backgroundMaterialize: true
|
|
501
|
+
});
|
|
502
|
+
|
|
503
|
+
// Subscribe to completion
|
|
504
|
+
api.slothlet.lifecycle.on("materialized:complete", (data) => {
|
|
505
|
+
console.log(`${data.total} modules materialized`);
|
|
506
|
+
});
|
|
507
|
+
|
|
508
|
+
// Or await all modules to be ready before serving traffic
|
|
509
|
+
await api.slothlet.materialize.wait();
|
|
510
|
+
|
|
511
|
+
// Check progress at any time
|
|
512
|
+
const stats = api.slothlet.materialize.get();
|
|
513
|
+
// { total, materialized, remaining, percentage }
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
> [!TIP]
|
|
516
517
|
> **Choose your strategy:**
|
|
517
518
|
>
|
|
518
|
-
> - **Startup-sensitive?** → Lazy mode (2.
|
|
519
|
-
> - **Call-intensive?** →
|
|
519
|
+
> - **Startup-sensitive?** → Lazy mode (2.2x faster startup)
|
|
520
|
+
> - **Call-intensive?** → Either mode (function calls essentially equal after materialization)
|
|
520
521
|
> - **Need predictability?** → Eager mode (no materialization delays)
|
|
521
522
|
> - **Large API, use subset?** → Lazy mode (memory efficient)
|
|
523
|
+
> - **Want lazy startup + eager runtime?** → Lazy mode + `backgroundMaterialize: true`
|
|
524
|
+
|
|
525
|
+
---
|
|
526
|
+
|
|
527
|
+
## 🎣 Hook System _(v3)_
|
|
528
|
+
|
|
529
|
+
### Hook Configuration
|
|
530
|
+
|
|
531
|
+
```js
|
|
532
|
+
// Simple enable (default pattern "**")
|
|
533
|
+
const api = await slothlet({ dir: "./api", hook: true });
|
|
534
|
+
|
|
535
|
+
// Enable with default pattern filter
|
|
536
|
+
const api = await slothlet({ dir: "./api", hook: "database.*" });
|
|
537
|
+
|
|
538
|
+
// Full configuration
|
|
539
|
+
const api = await slothlet({
|
|
540
|
+
dir: "./api",
|
|
541
|
+
hook: {
|
|
542
|
+
enabled: true,
|
|
543
|
+
pattern: "**",
|
|
544
|
+
suppressErrors: false // true = errors suppressed (returns undefined instead of throwing)
|
|
545
|
+
}
|
|
546
|
+
});
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
### Hook Types
|
|
550
|
+
|
|
551
|
+
- **`before`** - Executes before the function. Can modify arguments or short-circuit. **Must be synchronous.**
|
|
552
|
+
- **`after`** - Executes after successful completion. Can transform the return value.
|
|
553
|
+
- **`always`** - Read-only observer. Always executes (even on short-circuit). Return value ignored.
|
|
554
|
+
- **`error`** - Executes only when an error occurs. Receives error with source tracking.
|
|
555
|
+
|
|
556
|
+
### Basic Usage
|
|
557
|
+
|
|
558
|
+
The `hook.on(typePattern, handler, options)` signature uses `"type:pattern"` as the first argument:
|
|
559
|
+
|
|
560
|
+
```js
|
|
561
|
+
// Before hook - modify arguments
|
|
562
|
+
api.slothlet.hook.on(
|
|
563
|
+
"before:math.add",
|
|
564
|
+
({ path, args }) => {
|
|
565
|
+
return [args[0] * 2, args[1] * 2]; // Return array to replace arguments
|
|
566
|
+
// Return non-array non-undefined to short-circuit (skip function)
|
|
567
|
+
// Return undefined to continue with original args
|
|
568
|
+
},
|
|
569
|
+
{ id: "double-args", priority: 100 }
|
|
570
|
+
);
|
|
571
|
+
|
|
572
|
+
// After hook - transform result
|
|
573
|
+
api.slothlet.hook.on(
|
|
574
|
+
"after:math.*",
|
|
575
|
+
({ path, result }) => {
|
|
576
|
+
return result * 10; // Return value replaces result; undefined = no change
|
|
577
|
+
},
|
|
578
|
+
{ id: "scale-result" }
|
|
579
|
+
);
|
|
580
|
+
|
|
581
|
+
// Always hook - observe (read-only)
|
|
582
|
+
api.slothlet.hook.on(
|
|
583
|
+
"always:**",
|
|
584
|
+
({ path, result, hasError, errors }) => {
|
|
585
|
+
if (hasError) console.error(`${path} failed:`, errors);
|
|
586
|
+
else console.log(`${path} returned:`, result);
|
|
587
|
+
// Return value is ignored
|
|
588
|
+
},
|
|
589
|
+
{ id: "logger" }
|
|
590
|
+
);
|
|
591
|
+
|
|
592
|
+
// Error hook - monitor failures
|
|
593
|
+
api.slothlet.hook.on(
|
|
594
|
+
"error:**",
|
|
595
|
+
({ path, error, source }) => {
|
|
596
|
+
// source.type: "before" | "after" | "always" | "function"
|
|
597
|
+
console.error(`Error in ${path} (from ${source.type}):`, error.message);
|
|
598
|
+
},
|
|
599
|
+
{ id: "error-monitor" }
|
|
600
|
+
);
|
|
601
|
+
```
|
|
602
|
+
|
|
603
|
+
### Hook Subsets _(new in v3)_
|
|
604
|
+
|
|
605
|
+
Each hook type has three ordered execution phases:
|
|
606
|
+
|
|
607
|
+
| Subset | Order | Typical use |
|
|
608
|
+
|---|---|---|
|
|
609
|
+
| `"before"` | First | Auth checks, security validation |
|
|
610
|
+
| `"primary"` | Middle (default) | Main hook logic |
|
|
611
|
+
| `"after"` | Last | Audit trails, cleanup |
|
|
612
|
+
|
|
613
|
+
```js
|
|
614
|
+
// Auth check runs first - always
|
|
615
|
+
api.slothlet.hook.on(
|
|
616
|
+
"before:protected.*",
|
|
617
|
+
({ ctx }) => { if (!ctx.user) throw new Error("Unauthorized"); },
|
|
618
|
+
{ id: "auth", subset: "before", priority: 2000 }
|
|
619
|
+
);
|
|
620
|
+
|
|
621
|
+
// Main validation logic - default subset
|
|
622
|
+
api.slothlet.hook.on(
|
|
623
|
+
"before:protected.*",
|
|
624
|
+
({ args }) => { /* validate */ },
|
|
625
|
+
{ id: "validate" } // subset: "primary" by default
|
|
626
|
+
);
|
|
627
|
+
|
|
628
|
+
// Audit log always runs last
|
|
629
|
+
api.slothlet.hook.on(
|
|
630
|
+
"after:protected.*",
|
|
631
|
+
({ path, result }) => { /* log */ },
|
|
632
|
+
{ id: "audit", subset: "after" }
|
|
633
|
+
);
|
|
634
|
+
```
|
|
635
|
+
|
|
636
|
+
### Pattern Matching
|
|
637
|
+
|
|
638
|
+
| Syntax | Description | Example |
|
|
639
|
+
|---|---|---|
|
|
640
|
+
| `exact.path` | Exact match | `"before:math.add"` |
|
|
641
|
+
| `namespace.*` | All functions in namespace | `"after:math.*"` |
|
|
642
|
+
| `*.funcName` | Function name across namespaces | `"always:*.add"` |
|
|
643
|
+
| `**` | All functions | `"error:**"` |
|
|
644
|
+
| `{a,b}` | Brace expansion | `"before:{math,utils}.*"` |
|
|
645
|
+
| `!pattern` | Negation | `"before:!internal.*"` |
|
|
646
|
+
|
|
647
|
+
### Hook Management
|
|
648
|
+
|
|
649
|
+
```js
|
|
650
|
+
// Remove by ID
|
|
651
|
+
api.slothlet.hook.remove({ id: "my-hook" });
|
|
652
|
+
api.slothlet.hook.off("my-hook"); // alias
|
|
653
|
+
|
|
654
|
+
// Remove by filter
|
|
655
|
+
api.slothlet.hook.remove({ type: "before", pattern: "math.*" });
|
|
656
|
+
|
|
657
|
+
// Remove all
|
|
658
|
+
api.slothlet.hook.clear();
|
|
659
|
+
|
|
660
|
+
// List hooks
|
|
661
|
+
const all = api.slothlet.hook.list();
|
|
662
|
+
const active = api.slothlet.hook.list({ enabled: true });
|
|
663
|
+
|
|
664
|
+
// Enable / disable without unregistering
|
|
665
|
+
api.slothlet.hook.disable();
|
|
666
|
+
api.slothlet.hook.disable({ pattern: "math.*" });
|
|
667
|
+
api.slothlet.hook.enable();
|
|
668
|
+
api.slothlet.hook.enable({ type: "before" });
|
|
669
|
+
```
|
|
670
|
+
|
|
671
|
+
---
|
|
672
|
+
|
|
673
|
+
## 🔄 Per-Request Context _(v3 API)_
|
|
674
|
+
|
|
675
|
+
```js
|
|
676
|
+
const api = await slothlet({
|
|
677
|
+
dir: "./api",
|
|
678
|
+
context: { appName: "MyApp", version: "3.0" }
|
|
679
|
+
});
|
|
680
|
+
|
|
681
|
+
// run() - execute a function inside a scoped context
|
|
682
|
+
await api.slothlet.context.run({ userId: "alice", role: "admin" }, async () => {
|
|
683
|
+
// Inside this scope: context = { appName, version, userId, role }
|
|
684
|
+
await api.database.query();
|
|
685
|
+
await api.audit.log();
|
|
686
|
+
});
|
|
687
|
+
|
|
688
|
+
// scope() - return a new API object with merged context
|
|
689
|
+
const scopedApi = api.slothlet.context.scope({ userId: "bob" });
|
|
690
|
+
await scopedApi.database.query(); // context includes userId: "bob"
|
|
691
|
+
|
|
692
|
+
// Deep merge strategy
|
|
693
|
+
await api.slothlet.context.run(
|
|
694
|
+
{ nested: { prop: "value" } },
|
|
695
|
+
handler,
|
|
696
|
+
{ mergeStrategy: "deep" }
|
|
697
|
+
);
|
|
698
|
+
```
|
|
699
|
+
|
|
700
|
+
### Automatic EventEmitter Context Propagation
|
|
701
|
+
|
|
702
|
+
Context propagates automatically through EventEmitter callbacks:
|
|
703
|
+
|
|
704
|
+
```js
|
|
705
|
+
import net from "net";
|
|
706
|
+
import { context } from "@cldmv/slothlet/runtime";
|
|
707
|
+
|
|
708
|
+
export const server = {
|
|
709
|
+
async start() {
|
|
710
|
+
const tcpServer = net.createServer((socket) => {
|
|
711
|
+
console.log(`User ${context.userId} connected`);
|
|
712
|
+
|
|
713
|
+
socket.on("data", (data) => {
|
|
714
|
+
// Context preserved in all nested callbacks
|
|
715
|
+
console.log(`Data from ${context.userId}: ${data}`);
|
|
716
|
+
});
|
|
717
|
+
});
|
|
718
|
+
tcpServer.listen(3000);
|
|
719
|
+
}
|
|
720
|
+
};
|
|
721
|
+
```
|
|
722
|
+
|
|
723
|
+
> 📖 See [`docs/CONTEXT-PROPAGATION.md`](docs/CONTEXT-PROPAGATION.md)
|
|
724
|
+
|
|
725
|
+
---
|
|
726
|
+
|
|
727
|
+
## 🏷️ Metadata System
|
|
728
|
+
|
|
729
|
+
Tag API paths with metadata for authorization, auditing, and security.
|
|
730
|
+
|
|
731
|
+
```js
|
|
732
|
+
// Attach metadata when loading
|
|
733
|
+
await api.slothlet.api.add("plugins/trusted", "./trusted-dir", {
|
|
734
|
+
metadata: { trusted: true, securityLevel: "high" }
|
|
735
|
+
});
|
|
736
|
+
|
|
737
|
+
// Set metadata at runtime
|
|
738
|
+
api.slothlet.metadata.set("plugins.trusted.someFunc", { version: 2 });
|
|
739
|
+
api.slothlet.metadata.setGlobal({ environment: "production" });
|
|
740
|
+
api.slothlet.metadata.setFor("plugins/trusted", { owner: "core-team" });
|
|
741
|
+
api.slothlet.metadata.remove("plugins.old.func");
|
|
742
|
+
```
|
|
743
|
+
|
|
744
|
+
🔒 **For complete metadata documentation, see [docs/METADATA.md](https://github.com/CLDMV/slothlet/blob/master/docs/METADATA.md)**
|
|
745
|
+
|
|
746
|
+
---
|
|
747
|
+
|
|
748
|
+
## 🔁 Hot Reload / Dynamic API Management _(v3 API)_
|
|
749
|
+
|
|
750
|
+
```js
|
|
751
|
+
// Add new modules at runtime
|
|
752
|
+
await api.slothlet.api.add("newModule", "./new-module-path");
|
|
753
|
+
await api.slothlet.api.add("plugins", "./plugins", { collision: "merge" });
|
|
754
|
+
|
|
755
|
+
// Remove modules
|
|
756
|
+
await api.slothlet.api.remove("oldModule");
|
|
757
|
+
|
|
758
|
+
// Reload specific path or all modules
|
|
759
|
+
await api.slothlet.api.reload("database.*");
|
|
760
|
+
await api.slothlet.api.reload("plugins.auth");
|
|
761
|
+
```
|
|
762
|
+
|
|
763
|
+
> **Lazy mode reload behavior**: In lazy mode, reload restores modules to an unmaterialized proxy state - existing references are intentionally not preserved. Eager mode merges new module exports into the existing live wrapper, preserving references.
|
|
764
|
+
|
|
765
|
+
### Collision Modes _(new in v3)_
|
|
766
|
+
|
|
767
|
+
Control what happens when a loaded path already exists:
|
|
768
|
+
|
|
769
|
+
```js
|
|
770
|
+
const api = await slothlet({
|
|
771
|
+
dir: "./api",
|
|
772
|
+
api: {
|
|
773
|
+
collision: {
|
|
774
|
+
initial: "merge", // During initial load()
|
|
775
|
+
api: "skip" // During api.slothlet.api.add()
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
});
|
|
779
|
+
```
|
|
780
|
+
|
|
781
|
+
| Mode | Behavior |
|
|
782
|
+
|---|---|
|
|
783
|
+
| `"overwrite"` | Replace existing (default) |
|
|
784
|
+
| `"merge"` | Deep-merge new into existing |
|
|
785
|
+
| `"skip"` | Keep existing, ignore new |
|
|
786
|
+
| `"throw"` | Throw an error on conflict |
|
|
787
|
+
|
|
788
|
+
### Mutation Controls _(new in v3)_
|
|
789
|
+
|
|
790
|
+
Restrict which API operations are permitted:
|
|
791
|
+
|
|
792
|
+
```js
|
|
793
|
+
const api = await slothlet({
|
|
794
|
+
dir: "./api",
|
|
795
|
+
api: {
|
|
796
|
+
mutations: {
|
|
797
|
+
add: true,
|
|
798
|
+
remove: false, // Prevent removal in production
|
|
799
|
+
reload: false // Prevent reload in production
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
});
|
|
803
|
+
```
|
|
804
|
+
|
|
805
|
+
---
|
|
806
|
+
|
|
807
|
+
## ⚡ Lifecycle Events _(new in v3)_
|
|
808
|
+
|
|
809
|
+
Subscribe to internal module lifecycle events:
|
|
810
|
+
|
|
811
|
+
```js
|
|
812
|
+
// Available events
|
|
813
|
+
api.slothlet.lifecycle.on("materialized:complete", (data) => {
|
|
814
|
+
console.log(`${data.total} modules materialized`);
|
|
815
|
+
});
|
|
816
|
+
|
|
817
|
+
api.slothlet.lifecycle.on("impl:created", (data) => {
|
|
818
|
+
console.log(`Module created at ${data.apiPath}`);
|
|
819
|
+
});
|
|
820
|
+
|
|
821
|
+
api.slothlet.lifecycle.on("impl:changed", (data) => {
|
|
822
|
+
console.log(`Module at ${data.apiPath} was reloaded`);
|
|
823
|
+
});
|
|
824
|
+
|
|
825
|
+
api.slothlet.lifecycle.on("impl:removed", (data) => {
|
|
826
|
+
console.log(`Module at ${data.apiPath} was removed`);
|
|
827
|
+
});
|
|
828
|
+
|
|
829
|
+
// Unsubscribe
|
|
830
|
+
const handler = (data) => console.log(data);
|
|
831
|
+
api.slothlet.lifecycle.on("impl:changed", handler);
|
|
832
|
+
api.slothlet.lifecycle.off("impl:changed", handler);
|
|
833
|
+
```
|
|
834
|
+
|
|
835
|
+
**Available events**: `"materialized:complete"`, `"impl:created"`, `"impl:changed"`, `"impl:removed"`
|
|
836
|
+
|
|
837
|
+
> [!NOTE]
|
|
838
|
+
> `api.slothlet.lifecycle` exposes **`on` and `off` only**. `emit`, `subscribe`, and `unsubscribe` are internal - they are not present on the public API object.
|
|
839
|
+
|
|
840
|
+
---
|
|
841
|
+
|
|
842
|
+
## 📁 File Organization Best Practices
|
|
843
|
+
|
|
844
|
+
### ✅ Clean Folder Structure
|
|
845
|
+
|
|
846
|
+
```text
|
|
847
|
+
api/
|
|
848
|
+
├── config.mjs → api.config.*
|
|
849
|
+
├── math/
|
|
850
|
+
│ └── math.mjs → api.math.* (flattened - filename matches folder)
|
|
851
|
+
├── util/
|
|
852
|
+
│ ├── util.mjs → api.util.* (flattened methods)
|
|
853
|
+
│ ├── extract.mjs → api.util.extract.*
|
|
854
|
+
│ └── controller.mjs → api.util.controller.*
|
|
855
|
+
├── nested/
|
|
856
|
+
│ └── date/
|
|
857
|
+
│ └── date.mjs → api.nested.date.*
|
|
858
|
+
└── multi/
|
|
859
|
+
├── alpha.mjs → api.multi.alpha.*
|
|
860
|
+
└── beta.mjs → api.multi.beta.*
|
|
861
|
+
```
|
|
862
|
+
|
|
863
|
+
### ✅ Naming Conventions
|
|
864
|
+
|
|
865
|
+
- **Filename matches folder** → Auto-flattening (`math/math.mjs` → `api.math.*`)
|
|
866
|
+
- **Different filename** → Nested structure preserved
|
|
867
|
+
- **Dash-separated names** → camelCase API (`auto-ip.mjs` → `api.autoIP`)
|
|
868
|
+
- **Function name preferred** → Original capitalization kept over sanitized form (see [Rule 9](docs/API-RULES.md))
|
|
869
|
+
|
|
870
|
+
### ✅ Use `self` for Cross-Module Access
|
|
871
|
+
|
|
872
|
+
API modules must never import each other directly. Use Slothlet's live-binding system instead:
|
|
873
|
+
|
|
874
|
+
```js
|
|
875
|
+
// ❌ WRONG - breaks lazy loading and context isolation
|
|
876
|
+
import { math } from "./math/math.mjs";
|
|
877
|
+
|
|
878
|
+
// ✅ CORRECT - live binding always reflects current runtime state
|
|
879
|
+
import { self, context } from "@cldmv/slothlet/runtime";
|
|
880
|
+
|
|
881
|
+
export const myModule = {
|
|
882
|
+
async processData(input) {
|
|
883
|
+
const mathResult = self.math.add(2, 3); // Cross-module call via runtime
|
|
884
|
+
console.log(`Caller: ${context.userId}`); // Per-request context
|
|
885
|
+
return `Processed: ${input}, Math: ${mathResult}`;
|
|
886
|
+
}
|
|
887
|
+
};
|
|
888
|
+
```
|
|
522
889
|
|
|
523
890
|
---
|
|
524
891
|
|
|
@@ -545,118 +912,75 @@ Key highlights:
|
|
|
545
912
|
|
|
546
913
|
### Core Documentation
|
|
547
914
|
|
|
548
|
-
- **[API Documentation](https://github.com/CLDMV/slothlet/blob/master/docs/generated/API.md)** - Complete API reference with examples and detailed parameter descriptions
|
|
549
915
|
- **[Performance Analysis](https://github.com/CLDMV/slothlet/blob/master/docs/PERFORMANCE.md)** - Detailed benchmarks and recommendations
|
|
916
|
+
- **[Agent Usage Guide](AGENT-USAGE.md)** - Guide for AI agents building Slothlet API folders
|
|
550
917
|
- **[Contributing Guide](CONTRIBUTING.md)** - How to contribute to the project
|
|
551
918
|
- **[Security Policy](SECURITY.md)** - Security guidelines and reporting
|
|
552
919
|
- **[Test Documentation](api_tests)** - Comprehensive test module examples
|
|
553
920
|
|
|
554
921
|
### Technical Guides
|
|
555
922
|
|
|
556
|
-
- **[
|
|
923
|
+
- **[TypeScript Support](https://github.com/CLDMV/slothlet/blob/master/docs/TYPESCRIPT.md)** - Native TypeScript support: fast mode (esbuild), strict mode (tsc), and `.d.ts` type generation
|
|
924
|
+
- **[Hook System](https://github.com/CLDMV/slothlet/blob/master/docs/HOOKS.md)** - Complete hook system documentation with 4 hook types, three-phase subsets, pattern matching, and examples
|
|
557
925
|
- **[Context Propagation](https://github.com/CLDMV/slothlet/blob/master/docs/CONTEXT-PROPAGATION.md)** - EventEmitter and class instance context preservation
|
|
558
926
|
- **[Metadata System](https://github.com/CLDMV/slothlet/blob/master/docs/METADATA.md)** - Function metadata tagging and runtime introspection for security, authorization, and auditing
|
|
559
927
|
- **[Module Structure](https://github.com/CLDMV/slothlet/blob/master/docs/MODULE-STRUCTURE.md)** - Comprehensive module organization patterns and examples
|
|
560
|
-
- **[
|
|
928
|
+
- **[Sanitization](https://github.com/CLDMV/slothlet/blob/master/docs/SANITIZATION.md)** - Property name sanitization rules
|
|
929
|
+
- **[Internationalization](https://github.com/CLDMV/slothlet/blob/master/docs/I18N.md)** - i18n support, language configuration, and available translations
|
|
561
930
|
|
|
562
931
|
### API Rules & Transformation
|
|
563
932
|
|
|
564
|
-
- **[API Rules](
|
|
565
|
-
- **[API Rules Conditions](
|
|
933
|
+
- **[API Rules](docs/API-RULES.md)** - All 13 API transformation rules with verified test examples
|
|
934
|
+
- **[API Rules Conditions](docs/API-RULES/API-RULES-CONDITIONS.md)** - Complete technical reference of all conditional statements that control API generation
|
|
935
|
+
- **[API Flattening](docs/API-RULES/API-FLATTENING.md)** - Flattening rules with decision tree and benefits
|
|
936
|
+
|
|
937
|
+
---
|
|
566
938
|
|
|
567
|
-
|
|
939
|
+
## 🌟 Migration from v2.x
|
|
568
940
|
|
|
569
|
-
|
|
570
|
-
- **[v2.8](https://github.com/CLDMV/slothlet/blob/master/docs/changelog/v2.8.md)** - NPM security fixes and package workflow updates (December 26, 2025)
|
|
571
|
-
- **[v2.7](https://github.com/CLDMV/slothlet/blob/master/docs/changelog/v2.7.md)** - Hook System with 4 interceptor types (December 20, 2025)
|
|
572
|
-
- **[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)
|
|
573
|
-
- **[v2.5](https://github.com/CLDMV/slothlet/blob/master/docs/changelog/v2.5.md)** - Architectural consolidation and API consistency (October 20, 2025)
|
|
574
|
-
- **[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)
|
|
575
|
-
- **[v2.3](https://github.com/CLDMV/slothlet/blob/master/docs/changelog/v2.3.md)** - EventEmitter & Class Context Propagation (October 16, 2025)
|
|
576
|
-
- **[v2.2](https://github.com/CLDMV/slothlet/blob/master/docs/changelog/v2.2.md)** - Case preservation options (preserveAllUpper/preserveAllLower) (October 14, 2025)
|
|
577
|
-
- **[v2.1](https://github.com/CLDMV/slothlet/blob/master/docs/changelog/v2.1.md)** - Advanced sanitization with boundary patterns (October 12, 2025)
|
|
578
|
-
- **[v2.0](https://github.com/CLDMV/slothlet/blob/master/docs/changelog/v2.0.md)** - Complete Architectural Rewrite (September 9, 2025)
|
|
941
|
+
Upgrading from v2? See the **[Migration Guide](docs/MIGRATION.md)** for all breaking changes, full before/after code examples, a complete config diff, and a list of removed options.
|
|
579
942
|
|
|
580
943
|
---
|
|
581
944
|
|
|
582
945
|
## 🛡 Error Handling
|
|
583
946
|
|
|
584
|
-
|
|
585
|
-
> **Current Error Behavior**: Slothlet currently uses standard JavaScript error handling. Enhanced error handling with module suggestions is planned for v3.0.0 but not yet implemented.
|
|
586
|
-
|
|
587
|
-
**Current behavior:**
|
|
947
|
+
Slothlet v3 uses a rich `SlothletError` class with translated messages and contextual hints:
|
|
588
948
|
|
|
589
949
|
```javascript
|
|
590
950
|
try {
|
|
591
|
-
|
|
592
|
-
await api.nonexistent.method(); // Throws: "Cannot read properties of undefined (reading 'method')"
|
|
951
|
+
await api.slothlet.api.add("plugins", "./dir");
|
|
593
952
|
} catch (error) {
|
|
594
|
-
console.error(error.message); //
|
|
953
|
+
console.error(error.message); // Translated error message
|
|
954
|
+
console.error(error.hint); // Contextual hint for resolution
|
|
955
|
+
console.error(error.code); // Machine-readable error code
|
|
595
956
|
}
|
|
596
957
|
```
|
|
597
958
|
|
|
598
959
|
---
|
|
599
960
|
|
|
600
|
-
##
|
|
961
|
+
## 🏗️ Production & Development Modes
|
|
601
962
|
|
|
602
963
|
### Production Ready ✅
|
|
603
964
|
|
|
604
965
|
- **Eager Mode**: Stable, battle-tested, maximum performance
|
|
605
966
|
- **Lazy Mode**: Production-ready with copy-left optimization
|
|
606
|
-
- **
|
|
967
|
+
- **Background Materialization**: Lazy startup + eager runtime performance
|
|
607
968
|
- **Mixed Module Loading**: ESM/CJS interoperability fully supported
|
|
608
969
|
|
|
609
970
|
### Development Features 🛠️
|
|
610
971
|
|
|
972
|
+
- **Debug Mode**: Comprehensive i18n-translated logging via `--slothletdebug` flag or `SLOTHLET_DEBUG=true`
|
|
611
973
|
- **Development Check**: `devcheck.mjs` for environment validation
|
|
612
|
-
- **Debug Mode**: Comprehensive logging via `--slothletdebug` flag or `SLOTHLET_DEBUG=true`
|
|
613
|
-
- **Performance Monitoring**: Built-in timing and performance analysis
|
|
614
974
|
- **Source Detection**: Automatic `src/` vs `dist/` mode detection
|
|
615
|
-
|
|
616
|
-
### Experimental ⚠️
|
|
617
|
-
|
|
618
|
-
> [!WARNING]
|
|
619
|
-
> The following modes are in active development and not recommended for production use:
|
|
620
|
-
>
|
|
621
|
-
> - **Worker Mode**: Thread isolation (in development)
|
|
622
|
-
> - **Fork Mode**: Process isolation (in development)
|
|
623
|
-
> - **Child Mode**: Child process execution (in development)
|
|
624
|
-
> - **VM Mode**: Virtual machine context (in development)
|
|
625
|
-
|
|
626
|
-
---
|
|
627
|
-
|
|
628
|
-
## 🌟 Migration from v1.x
|
|
629
|
-
|
|
630
|
-
### Key Changes
|
|
631
|
-
|
|
632
|
-
1. **Import paths**: `@cldmv/slothlet` instead of specific file paths
|
|
633
|
-
2. **Configuration**: New options (`api_mode`, `context`, `reference`, `hooks`)
|
|
634
|
-
3. **Function names**: Enhanced preservation of original capitalization
|
|
635
|
-
4. **Module structure**: Mixed ESM/CJS support
|
|
636
|
-
5. **Live bindings**: Dual runtime system with AsyncLocalStorage and live-bindings options
|
|
637
|
-
6. **Automatic instances**: No more query strings or `withInstanceId()` methods
|
|
638
|
-
|
|
639
|
-
### Migration Steps
|
|
640
|
-
|
|
641
|
-
```javascript
|
|
642
|
-
// v1.3.x - Multiple instances required query strings or withInstanceId()
|
|
643
|
-
const api1 = await slothlet({ dir: "./api?instanceId=alice" });
|
|
644
|
-
const api2 = slothlet.withInstanceId("bob");
|
|
645
|
-
const bobApi = await api2({ dir: "./api" });
|
|
646
|
-
|
|
647
|
-
// v2.x - Automatic instance isolation (no query strings needed)
|
|
648
|
-
const api1 = await slothlet({ dir: "./api", context: { tenant: "alice" } });
|
|
649
|
-
const api2 = await slothlet({ dir: "./api", context: { tenant: "bob" } });
|
|
650
|
-
// Instances completely isolated with their own contexts
|
|
651
|
-
```
|
|
975
|
+
- **API Inspection**: `console.log(api.math)` shows real module contents (v3+)
|
|
652
976
|
|
|
653
977
|
---
|
|
654
978
|
|
|
655
979
|
## 🤝 Contributing
|
|
656
980
|
|
|
657
|
-
We welcome contributions!
|
|
981
|
+
We welcome contributions! Please:
|
|
658
982
|
|
|
659
|
-
1. **Review the code** in `src/lib
|
|
983
|
+
1. **Review the code** in `src/lib/` for implementation details
|
|
660
984
|
2. **Report issues** with detailed reproduction steps
|
|
661
985
|
3. **Submit pull requests** with comprehensive tests
|
|
662
986
|
4. **Provide feedback** on API design and performance
|
|
@@ -687,11 +1011,7 @@ Apache-2.0 © Shinrai / CLDMV
|
|
|
687
1011
|
|
|
688
1012
|
## 🙏 Acknowledgments
|
|
689
1013
|
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
**🎉 Welcome to the future of module loading with Slothlet!**
|
|
693
|
-
|
|
694
|
-
> _Where sophisticated architecture meets blazing performance - slothlet is anything but slow._
|
|
1014
|
+
To my wife and children - thank you for your patience, your encouragement, and the countless hours you gave me to build this. None of it would exist without your support.
|
|
695
1015
|
|
|
696
1016
|
<!-- [github release]: https://img.shields.io/github/v/release/CLDMV/slothlet?style=for-the-badge&logo=github&logoColor=white&labelColor=181717 -->
|
|
697
1017
|
<!-- [github_release_url]: https://github.com/CLDMV/slothlet/releases -->
|
|
@@ -700,10 +1020,6 @@ Slothlet v2.0 represents a complete architectural rewrite with enterprise-grade
|
|
|
700
1020
|
[npm_version_url]: https://www.npmjs.com/package/@cldmv/slothlet
|
|
701
1021
|
[last commit]: https://img.shields.io/github/last-commit/CLDMV/slothlet?style=for-the-badge&logo=github&logoColor=white&labelColor=181717
|
|
702
1022
|
[last_commit_url]: https://github.com/CLDMV/slothlet/commits
|
|
703
|
-
|
|
704
|
-
<!-- [release date]: https://img.shields.io/github/release-date/CLDMV/slothlet?style=for-the-badge&logo=github&logoColor=white&labelColor=181717 -->
|
|
705
|
-
<!-- [release_date_url]: https://github.com/CLDMV/slothlet/releases -->
|
|
706
|
-
|
|
707
1023
|
[npm last update]: https://img.shields.io/npm/last-update/%40cldmv%2Fslothlet?style=for-the-badge&logo=npm&logoColor=white&labelColor=CB3837
|
|
708
1024
|
[npm_last_update_url]: https://www.npmjs.com/package/@cldmv/slothlet
|
|
709
1025
|
[codefactor]: https://img.shields.io/codefactor/grade/github/CLDMV/slothlet?style=for-the-badge&logo=codefactor&logoColor=white&labelColor=F44A6A
|