@cldmv/slothlet 1.0.1 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +862 -73
- package/dist/lib/engine/README.md +21 -0
- package/dist/lib/engine/slothlet_child.mjs +58 -0
- package/dist/lib/engine/slothlet_engine.mjs +371 -0
- package/dist/lib/engine/slothlet_esm.mjs +229 -0
- package/dist/lib/engine/slothlet_helpers.mjs +454 -0
- package/dist/lib/engine/slothlet_worker.mjs +148 -0
- package/dist/lib/helpers/resolve-from-caller.mjs +141 -0
- package/dist/lib/helpers/sanitize.mjs +78 -0
- package/dist/lib/modes/slothlet_eager.mjs +80 -0
- package/dist/lib/modes/slothlet_lazy.mjs +342 -0
- package/dist/lib/runtime/runtime.mjs +249 -0
- package/dist/slothlet.mjs +1092 -0
- package/index.cjs +81 -0
- package/index.mjs +76 -0
- package/package.json +136 -14
- package/types/dist/lib/engine/slothlet_child.d.mts +2 -0
- package/types/dist/lib/engine/slothlet_child.d.mts.map +1 -0
- package/types/dist/lib/engine/slothlet_engine.d.mts +31 -0
- package/types/dist/lib/engine/slothlet_engine.d.mts.map +1 -0
- package/types/dist/lib/engine/slothlet_esm.d.mts +19 -0
- package/types/dist/lib/engine/slothlet_esm.d.mts.map +1 -0
- package/types/dist/lib/engine/slothlet_helpers.d.mts +24 -0
- package/types/dist/lib/engine/slothlet_helpers.d.mts.map +1 -0
- package/types/dist/lib/engine/slothlet_worker.d.mts +2 -0
- package/types/dist/lib/engine/slothlet_worker.d.mts.map +1 -0
- package/types/dist/lib/helpers/resolve-from-caller.d.mts +149 -0
- package/types/dist/lib/helpers/resolve-from-caller.d.mts.map +1 -0
- package/types/dist/lib/helpers/sanitize.d.mts +138 -0
- package/types/dist/lib/helpers/sanitize.d.mts.map +1 -0
- package/types/dist/lib/modes/slothlet_eager.d.mts +66 -0
- package/types/dist/lib/modes/slothlet_eager.d.mts.map +1 -0
- package/types/dist/lib/modes/slothlet_lazy.d.mts +32 -0
- package/types/dist/lib/modes/slothlet_lazy.d.mts.map +1 -0
- package/types/dist/lib/runtime/runtime.d.mts +49 -0
- package/types/dist/lib/runtime/runtime.d.mts.map +1 -0
- package/types/dist/slothlet.d.mts +110 -0
- package/types/dist/slothlet.d.mts.map +1 -0
- package/types/index.d.mts +23 -0
- package/slothlet.mjs +0 -1218
package/README.md
CHANGED
|
@@ -1,115 +1,904 @@
|
|
|
1
1
|
# @cldmv/slothlet
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-

|
|
7
|
-

|
|
3
|
+
<div align="center">
|
|
4
|
+
<img src="images/slothlet-logo-v1-horizontal-transparent.png" alt="Slothlet Logo" width="600">
|
|
5
|
+
</div>
|
|
8
6
|
|
|
9
|
-
|
|
7
|
+
**@cldmv/slothlet** is a sophisticated module loading framework that revolutionizes how you work with massive APIs in Node.js. Built for developers who demand smart, efficient module loading without compromising performance or developer experience.
|
|
8
|
+
|
|
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
|
+
|
|
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
|
+
|
|
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
|
+
|
|
15
|
+
> _"slothlet is anything but slow."_
|
|
16
|
+
|
|
17
|
+
[![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
|
+
|
|
19
|
+
> [!NOTE]
|
|
20
|
+
> **🚀 Production Ready Modes:**
|
|
21
|
+
>
|
|
22
|
+
> - **Eager Mode**: Fully stable and production-ready for immediate module loading
|
|
23
|
+
> - **Lazy Mode**: Production-ready with advanced copy-left materialization and 4.3x faster startup (1.1x slower function calls)
|
|
24
|
+
|
|
25
|
+
> [!CAUTION]
|
|
26
|
+
> **⚙️ Experimental Modes:**
|
|
10
27
|
>
|
|
11
|
-
> -
|
|
12
|
-
> - **Lazy mode** has been tested and works for most use cases.
|
|
13
|
-
> - **Experimental modes** (such as worker, child process, and advanced context binding) are in development and may not be fully functional or stable.
|
|
28
|
+
> - **Worker, Fork, Child, VM modes**: In active development, not recommended for production use
|
|
14
29
|
>
|
|
15
|
-
> Please report issues
|
|
30
|
+
> Please report issues and contribute feedback to help improve the experimental features.
|
|
31
|
+
|
|
32
|
+
[![Contributors]][contributors_url] [![Sponsor shinrai]][sponsor_url]
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## ✨ What's New in v2.0
|
|
37
|
+
|
|
38
|
+
### 🎯 **Complete Architectural Rewrite**
|
|
39
|
+
|
|
40
|
+
v2.0 represents a ground-up rewrite with enterprise-grade features:
|
|
41
|
+
|
|
42
|
+
- **Universal Module Support**: Load both ESM (`.mjs`) and CommonJS (`.cjs`) files seamlessly
|
|
43
|
+
- **AsyncLocalStorage Integration**: Advanced context isolation and live-binding system
|
|
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
|
|
47
|
+
|
|
48
|
+
### 🏗️ **Enhanced Architecture**
|
|
49
|
+
|
|
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
|
+
### 📊 **Performance Optimizations**
|
|
56
|
+
|
|
57
|
+
- **Startup**: Lazy mode 4.3x faster (564.17μs vs 2.45ms)
|
|
58
|
+
- **Function Calls**: Eager mode 1.1x faster (0.65μs vs 0.72μs) after materialization
|
|
59
|
+
- **Memory**: On-demand loading scales with actual usage
|
|
60
|
+
- **Predictability**: Consistent performance characteristics per mode
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## 🚀 Key Features
|
|
65
|
+
|
|
66
|
+
### 🎯 **Dual Loading Strategies**
|
|
67
|
+
|
|
68
|
+
- **Eager Loading**: Immediate loading for maximum performance in production environments
|
|
69
|
+
- **Lazy Loading**: Copy-left materialization with look-ahead proxies (4.3x faster startup, 1.1x slower calls after materialization)
|
|
70
|
+
|
|
71
|
+
> [!IMPORTANT]
|
|
72
|
+
> **Function Call Patterns:**
|
|
73
|
+
>
|
|
74
|
+
> - **Lazy Mode**: ALL function calls must be awaited (`await api.math.add(2, 3)`) due to materialization process
|
|
75
|
+
> - **Eager Mode**: Functions behave as originally defined - sync functions are sync (`api.math.add(2, 3)`), async functions are async (`await api.async.process()`)
|
|
76
|
+
|
|
77
|
+
### ⚡ Performance Excellence
|
|
78
|
+
|
|
79
|
+
- **📊 For comprehensive performance analysis, benchmarks, and recommendations, see [PERFORMANCE.md](PERFORMANCE.md)**
|
|
80
|
+
|
|
81
|
+
### 🔧 **Smart API Management**
|
|
16
82
|
|
|
17
|
-
|
|
83
|
+
- **Callable Interface**: Use `slothlet(options)` for direct API creation
|
|
84
|
+
- **Automatic Flattening**: Single-file modules become direct API properties (`math/math.mjs` → `api.math`)
|
|
85
|
+
- **Intelligent Naming**: Dash-separated names convert automatically (`root-math.mjs` → `api.rootMath`)
|
|
86
|
+
- **Function Name Preservation**: Maintains original capitalization (`auto-ip.mjs` with `autoIP` → `api.autoIP`)
|
|
87
|
+
- **Hybrid Exports**: Support for callable APIs with methods, default + named exports, and mixed patterns
|
|
18
88
|
|
|
19
|
-
|
|
89
|
+
> [!TIP]
|
|
90
|
+
> **📁 For comprehensive examples of API flattening, naming conventions, and function preservation patterns, see the test modules in [api_tests/](api_tests/) and their documentation in [docs/api_tests/](docs/api_tests/)**
|
|
20
91
|
|
|
21
|
-
|
|
22
|
-
- **Eager loading:** Optionally load all modules up front for maximum performance.
|
|
23
|
-
- **Automatic flattening:** Single-file modules (e.g., `math/math.mjs`) become `api.math`.
|
|
24
|
-
- **CamelCase mapping:** Filenames and folders with dashes are mapped to camelCase API properties (e.g., `root-math.mjs` → `api.rootMath`).
|
|
25
|
-
- **Descriptive errors:** Throws clear errors for missing API paths or methods.
|
|
26
|
-
- **Configurable:** Set root directory and lazy loading depth.
|
|
27
|
-
- **ESM-first:** Clean, standards-based API.
|
|
28
|
-
- **TypeScript-friendly:** JSDoc-annotated API for editor support.
|
|
29
|
-
- **Lightweight:** No dependencies, minimal footprint.
|
|
92
|
+
### 🔗 **Advanced Binding System**
|
|
30
93
|
|
|
31
|
-
|
|
94
|
+
- **Live Bindings**: Dynamic context and reference binding for runtime API mutation
|
|
95
|
+
- **AsyncLocalStorage**: Per-instance context isolation with seamless integration
|
|
96
|
+
- **Copy-Left Preservation**: Materialized functions stay materialized, preserving performance gains
|
|
97
|
+
- **Bubble-Up Updates**: Parent API synchronization ensures consistency across the API tree
|
|
98
|
+
- **Mixed Module Support**: Seamlessly blend ESM and CommonJS modules in the same API
|
|
32
99
|
|
|
33
|
-
|
|
100
|
+
### 🛠 **Developer Experience**
|
|
101
|
+
|
|
102
|
+
- **Standard Error Handling**: Clear JavaScript errors with plans for enhanced descriptive errors in v2.1.0
|
|
103
|
+
- **TypeScript-Friendly**: Comprehensive JSDoc annotations for excellent editor support with auto-generated declarations
|
|
104
|
+
- **Configurable Debug**: Detailed logging for development and troubleshooting via CLI flags or environment variables
|
|
105
|
+
- **Multiple Instances**: Parameter-based isolation for complex applications with instance ID management
|
|
106
|
+
- **Development Checks**: Built-in environment detection with silent production behavior
|
|
107
|
+
|
|
108
|
+
### 🏗 **Architecture & Compatibility**
|
|
109
|
+
|
|
110
|
+
- **ESM-First**: Built for modern JavaScript with full ES module support
|
|
111
|
+
- **Universal Loading**: CommonJS and ESM files work together seamlessly
|
|
112
|
+
- **Zero Dependencies**: Lightweight footprint with no external dependencies
|
|
113
|
+
- **Cross-Platform**: Works seamlessly across all Node.js environments
|
|
114
|
+
- **Extensible**: Modular architecture designed for future plugin system (in development)
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## 📦 Installation
|
|
119
|
+
|
|
120
|
+
### Requirements
|
|
121
|
+
|
|
122
|
+
- **Node.js v16.4.0 or higher** (for stable AsyncLocalStorage support)
|
|
123
|
+
- **ESM support** (ES modules with `import`/`export`)
|
|
124
|
+
|
|
125
|
+
> [!IMPORTANT]
|
|
126
|
+
> **v2.x Breaking Change**: Slothlet v2.x requires AsyncLocalStorage for its comprehensive live-binding system, which was stabilized in Node.js v16.4.0+ (June 2021). If you need older Node.js versions, please use slothlet v1.x (which requires Node.js v12.20.0+ (November 2020) for ESM support, dynamic imports, and query string imports). Note that v1.x live-binding worked in ESM (including multiple APIs via query strings) but was not available for multiple API instances in CommonJS.
|
|
127
|
+
|
|
128
|
+
### Install
|
|
129
|
+
|
|
130
|
+
```bash
|
|
34
131
|
npm install @cldmv/slothlet
|
|
35
132
|
```
|
|
36
133
|
|
|
37
|
-
|
|
134
|
+
---
|
|
38
135
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
136
|
+
## 🚀 Quick Start
|
|
137
|
+
|
|
138
|
+
### ESM (ES Modules)
|
|
139
|
+
|
|
140
|
+
```javascript
|
|
141
|
+
import slothlet from "@cldmv/slothlet";
|
|
142
|
+
|
|
143
|
+
// Direct usage - eager mode by default (auto-detects callable interface)
|
|
144
|
+
const api = await slothlet({
|
|
145
|
+
dir: "./api",
|
|
146
|
+
context: { user: "alice" }
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
// Eager mode: Functions behave as originally defined
|
|
150
|
+
const result = api.math.add(2, 3); // Sync function - no await needed
|
|
151
|
+
const greeting = api("World"); // Instant if callable
|
|
152
|
+
|
|
153
|
+
// Original async functions still need await in eager mode
|
|
154
|
+
const asyncResult = await api.async.processData({ data: "async" });
|
|
155
|
+
|
|
156
|
+
// Access both ESM and CJS modules seamlessly
|
|
157
|
+
const esmResult = api.mathEsm.multiply(4, 5); // 20 (sync)
|
|
158
|
+
const cjsResult = await api.mathCjs.divide(10, 2); // 5 (if originally async)
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### CommonJS (CJS)
|
|
162
|
+
|
|
163
|
+
```javascript
|
|
164
|
+
const slothlet = require("@cldmv/slothlet");
|
|
165
|
+
|
|
166
|
+
// Same usage pattern works with CommonJS
|
|
167
|
+
const api = await slothlet({
|
|
168
|
+
dir: "./api",
|
|
169
|
+
context: { env: "production" }
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
const result = api.math.multiply(4, 5); // 20
|
|
173
|
+
const mixedResult = await api.interop.processData({ data: "test" }); // CJS+ESM interop
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### Lazy Loading Mode
|
|
177
|
+
|
|
178
|
+
```javascript
|
|
179
|
+
import slothlet from "@cldmv/slothlet";
|
|
44
180
|
|
|
45
|
-
|
|
181
|
+
// Lazy mode with copy-left materialization (opt-in)
|
|
182
|
+
const api = await slothlet({
|
|
183
|
+
lazy: true,
|
|
184
|
+
dir: "./api",
|
|
185
|
+
apiDepth: 3
|
|
186
|
+
});
|
|
46
187
|
|
|
47
|
-
|
|
188
|
+
// First access: ~310μs (materialization overhead)
|
|
189
|
+
const result1 = await api.math.add(2, 3);
|
|
190
|
+
|
|
191
|
+
// Subsequent access: ~0.5μs (materialized function)
|
|
192
|
+
const result2 = await api.math.add(5, 7); // 700x faster than first call!
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### Advanced Configuration
|
|
196
|
+
|
|
197
|
+
```javascript
|
|
198
|
+
import slothlet from "@cldmv/slothlet";
|
|
199
|
+
|
|
200
|
+
const api = await slothlet({
|
|
201
|
+
dir: "./api",
|
|
202
|
+
lazy: false, // Loading strategy
|
|
203
|
+
api_mode: "auto", // API structure behavior
|
|
204
|
+
apiDepth: Infinity, // Directory traversal depth
|
|
205
|
+
debug: false, // Enable verbose logging
|
|
206
|
+
context: {
|
|
207
|
+
// Injected into live-binding
|
|
208
|
+
user: "alice",
|
|
209
|
+
env: "production",
|
|
210
|
+
config: { timeout: 5000 }
|
|
211
|
+
},
|
|
212
|
+
reference: {
|
|
213
|
+
// Merged into API root
|
|
214
|
+
version: "2.0.0",
|
|
215
|
+
helpers: {
|
|
216
|
+
/* ... */
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### Multiple Instances
|
|
223
|
+
|
|
224
|
+
In v2.x, each call to `slothlet(options)` automatically creates a new isolated instance with its own context and configuration:
|
|
225
|
+
|
|
226
|
+
#### ESM (ES Modules)
|
|
227
|
+
|
|
228
|
+
```javascript
|
|
48
229
|
import slothlet from "@cldmv/slothlet";
|
|
49
230
|
|
|
50
|
-
//
|
|
51
|
-
const
|
|
231
|
+
// Each call creates a new isolated instance automatically
|
|
232
|
+
const api1 = await slothlet({ dir: "./api1", context: { tenant: "alice" } });
|
|
233
|
+
const api2 = await slothlet({ dir: "./api2", context: { tenant: "bob" } });
|
|
234
|
+
|
|
235
|
+
// Instances are completely isolated
|
|
236
|
+
console.log(api1.context.tenant); // "alice"
|
|
237
|
+
console.log(api2.context.tenant); // "bob"
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
#### CommonJS (CJS)
|
|
241
|
+
|
|
242
|
+
```javascript
|
|
243
|
+
const slothlet = require("@cldmv/slothlet");
|
|
244
|
+
|
|
245
|
+
// Each call creates a new isolated instance automatically
|
|
246
|
+
const api1 = await slothlet({ dir: "./api1", context: { tenant: "alice" } });
|
|
247
|
+
const api2 = await slothlet({ dir: "./api2", context: { tenant: "bob" } });
|
|
248
|
+
|
|
249
|
+
// Instances are completely isolated with their own AsyncLocalStorage contexts
|
|
250
|
+
console.log(api1.context.tenant); // "alice"
|
|
251
|
+
console.log(api2.context.tenant); // "bob"
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
> [!NOTE]
|
|
255
|
+
> **v2.x Simplification**: Unlike v1.x which required query string parameters or `withInstanceId()` methods, v2.x automatically creates isolated instances with each `slothlet()` call, leveraging AsyncLocalStorage for complete context separation.
|
|
256
|
+
|
|
257
|
+
---
|
|
258
|
+
|
|
259
|
+
## 📚 API Reference
|
|
260
|
+
|
|
261
|
+
### Core Methods
|
|
262
|
+
|
|
263
|
+
#### `slothlet(options)` ⇒ `Promise<object>`
|
|
264
|
+
|
|
265
|
+
Creates and loads an API instance with the specified configuration.
|
|
266
|
+
|
|
267
|
+
**Parameters:**
|
|
268
|
+
|
|
269
|
+
| Param | Type | Description |
|
|
270
|
+
| ------- | -------- | --------------------- |
|
|
271
|
+
| options | `object` | Configuration options |
|
|
272
|
+
|
|
273
|
+
**Returns:** `Promise<object>` - The bound API object
|
|
52
274
|
|
|
53
|
-
|
|
54
|
-
const sum = await api.math.add(2, 3); // 5
|
|
55
|
-
const upper = await api.string.upper("abc"); // 'ABC'
|
|
56
|
-
const today = await api.nested.date.today(); // '2025-08-15'
|
|
275
|
+
**Options:**
|
|
57
276
|
|
|
277
|
+
| Option | Type | Default | Description |
|
|
278
|
+
| ----------- | --------- | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
279
|
+
| `dir` | `string` | `"api"` | Directory to load API modules from. Can be absolute or relative path. If relative, resolved from process.cwd(). |
|
|
280
|
+
| `lazy` | `boolean` | `false` | Loading strategy - `true` for lazy loading (on-demand), `false` for eager loading (immediate) |
|
|
281
|
+
| `apiDepth` | `number` | `Infinity` | Directory traversal depth control - `0` for root only, `Infinity` for all levels |
|
|
282
|
+
| `debug` | `boolean` | `false` | Enable verbose logging. Can also be set via `--slothletdebug` command line flag or `SLOTHLET_DEBUG=true` environment variable |
|
|
283
|
+
| `mode` | `string` | `"singleton"` | Execution environment mode - `"singleton"`, `"vm"`, `"worker"`, or `"fork"` |
|
|
284
|
+
| `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) |
|
|
285
|
+
| `context` | `object` | `{}` | Context data object injected into live-binding `context` reference. Available to all loaded modules via `import { context } from '@cldmv/slothlet/runtime'` |
|
|
286
|
+
| `reference` | `object` | `{}` | Reference object merged into the API root level. Properties not conflicting with loaded modules are added directly to the API |
|
|
58
287
|
|
|
288
|
+
#### `slothlet.getApi()` ⇒ `object`
|
|
59
289
|
|
|
60
|
-
|
|
61
|
-
const api = await slothlet.create({ lazy: false, dir: "./api_test" context });
|
|
290
|
+
Returns the raw API object (Proxy or plain object).
|
|
62
291
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
292
|
+
**Returns:** `function | object` - The raw API object or function
|
|
293
|
+
|
|
294
|
+
#### `slothlet.getBoundApi()` ⇒ `object`
|
|
295
|
+
|
|
296
|
+
Returns the bound API object with context and reference.
|
|
297
|
+
|
|
298
|
+
**Returns:** `function | object` - The bound API object or function with live bindings and context
|
|
299
|
+
|
|
300
|
+
#### `slothlet.isLoaded()` ⇒ `boolean`
|
|
301
|
+
|
|
302
|
+
Returns true if the API is loaded.
|
|
303
|
+
|
|
304
|
+
**Returns:** `boolean` - Whether the API has been loaded
|
|
305
|
+
|
|
306
|
+
#### `slothlet.shutdown()` ⇒ `Promise<void>`
|
|
307
|
+
|
|
308
|
+
Gracefully shuts down the API and cleans up resources.
|
|
309
|
+
|
|
310
|
+
**Returns:** `Promise<void>` - Resolves when shutdown is complete
|
|
311
|
+
|
|
312
|
+
> [!NOTE]
|
|
313
|
+
> **📚 For detailed API documentation with comprehensive parameter descriptions, method signatures, and examples, see [docs/API.md](docs/API.md)**
|
|
314
|
+
|
|
315
|
+
### Live Bindings
|
|
316
|
+
|
|
317
|
+
Access live-bound references in your API modules:
|
|
318
|
+
|
|
319
|
+
```javascript
|
|
320
|
+
// Create API with reference functions
|
|
321
|
+
const api = await slothlet({
|
|
322
|
+
dir: "./api",
|
|
323
|
+
reference: {
|
|
324
|
+
md5: (str) => crypto.createHash("md5").update(str).digest("hex"),
|
|
325
|
+
version: "2.0.0",
|
|
326
|
+
utils: { format: (msg) => `[LOG] ${msg}` }
|
|
327
|
+
}
|
|
328
|
+
});
|
|
67
329
|
```
|
|
68
330
|
|
|
69
|
-
|
|
331
|
+
```javascript
|
|
332
|
+
// In your API modules (ESM)
|
|
333
|
+
import { self, context, reference } from "@cldmv/slothlet/runtime";
|
|
70
334
|
|
|
71
|
-
|
|
335
|
+
export function myFunction() {
|
|
336
|
+
console.log(context.user); // Access live context
|
|
337
|
+
return self.otherModule.helper(); // Access other API modules
|
|
72
338
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
- `slothlet.getBoundApi()` — Returns the bound API object (with context/reference).
|
|
78
|
-
- `slothlet.isLoaded()` — Returns true if the API is loaded.
|
|
79
|
-
- `slothlet.shutdown()` — Gracefully shuts down the API and internal resources.
|
|
339
|
+
// Reference functions are available directly on self
|
|
340
|
+
const hash = self.md5("hello world"); // Access reference function
|
|
341
|
+
console.log(self.version); // Access reference data
|
|
342
|
+
}
|
|
80
343
|
|
|
81
|
-
|
|
344
|
+
// Mixed module example (ESM accessing CJS)
|
|
345
|
+
export function processData(data) {
|
|
346
|
+
// Call a CJS module from ESM
|
|
347
|
+
const processed = self.cjsModule.process(data);
|
|
82
348
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
349
|
+
// Use reference utilities directly
|
|
350
|
+
const logged = self.utils.format(`Processed: ${processed}`);
|
|
351
|
+
return self.md5(logged); // Hash the result
|
|
352
|
+
}
|
|
353
|
+
```
|
|
87
354
|
|
|
88
|
-
|
|
355
|
+
```javascript
|
|
356
|
+
// In your CJS modules
|
|
357
|
+
const { self, context, reference } = require("@cldmv/slothlet/runtime");
|
|
89
358
|
|
|
90
|
-
|
|
91
|
-
|
|
359
|
+
function cjsFunction(data) {
|
|
360
|
+
console.log(context.env); // Access live context
|
|
92
361
|
|
|
93
|
-
|
|
362
|
+
// Reference functions available directly on self
|
|
363
|
+
const hash = self.md5(data); // Direct access to reference function
|
|
94
364
|
|
|
95
|
-
|
|
96
|
-
|
|
365
|
+
return self.esmModule.transform(hash); // Access ESM modules from CJS
|
|
366
|
+
}
|
|
97
367
|
|
|
98
|
-
|
|
368
|
+
module.exports = { cjsFunction };
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
### API Mode Configuration
|
|
372
|
+
|
|
373
|
+
The `api_mode` option controls how slothlet handles root-level default function exports:
|
|
374
|
+
|
|
375
|
+
#### Auto-Detection (Recommended)
|
|
99
376
|
|
|
100
|
-
|
|
377
|
+
```javascript
|
|
378
|
+
const api = await slothlet({
|
|
379
|
+
api_mode: "auto" // Default - automatically detects structure
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
// If you have a root-level function export:
|
|
383
|
+
// root-function.mjs: export default function(name) { return `Hello, ${name}!` }
|
|
384
|
+
// Result: api("World") works AND api.otherModule.method() works
|
|
385
|
+
|
|
386
|
+
// If you only have object exports:
|
|
387
|
+
// Result: api.math.add() works, api("World") doesn't exist
|
|
388
|
+
```
|
|
101
389
|
|
|
102
|
-
|
|
390
|
+
#### Explicit Function Mode
|
|
103
391
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
392
|
+
```javascript
|
|
393
|
+
const api = await slothlet({
|
|
394
|
+
api_mode: "function" // Force callable interface
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
// Always creates callable API even without root default export
|
|
398
|
+
// Useful when you know you have root functions
|
|
399
|
+
const result = api("World"); // Calls root default function
|
|
400
|
+
const math = api.math.add(2, 3); // Also access other modules
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
#### Explicit Object Mode
|
|
404
|
+
|
|
405
|
+
```javascript
|
|
406
|
+
const api = await slothlet({
|
|
407
|
+
api_mode: "object" // Force object-only interface
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
// Always creates object interface even with root default export
|
|
411
|
+
// api("World") won't work, but api.rootFunction("World") will
|
|
412
|
+
const result = api.rootFunction("World"); // Access via property
|
|
413
|
+
const math = api.math.add(2, 3); // Normal module access
|
|
414
|
+
```
|
|
107
415
|
|
|
108
|
-
|
|
416
|
+
---
|
|
109
417
|
|
|
110
|
-
|
|
111
|
-
- Only loads modules when accessed (lazy) or all at once (eager)
|
|
418
|
+
## 🏗 Module Structure & Examples
|
|
112
419
|
|
|
113
|
-
|
|
420
|
+
Slothlet supports sophisticated module organization patterns with seamless ESM/CJS interoperability:
|
|
421
|
+
|
|
422
|
+
### Root-Level Modules
|
|
423
|
+
|
|
424
|
+
```text
|
|
425
|
+
root-math.mjs → api.rootMath (dash-to-camelCase)
|
|
426
|
+
rootstring.mjs → api.rootstring
|
|
427
|
+
config.mjs → api.config
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
### Single-File Modules
|
|
431
|
+
|
|
432
|
+
```text
|
|
433
|
+
math/math.mjs → api.math (automatic flattening)
|
|
434
|
+
string/string.mjs → api.string
|
|
435
|
+
util/util.cjs → api.util (CJS support)
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
### Multi-File Modules
|
|
439
|
+
|
|
440
|
+
```text
|
|
441
|
+
multi/
|
|
442
|
+
├── alpha.mjs → api.multi.alpha
|
|
443
|
+
├── beta.mjs → api.multi.beta
|
|
444
|
+
└── gamma.cjs → api.multi.gamma (mixed ESM/CJS)
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
### Function-Based Modules
|
|
448
|
+
|
|
449
|
+
```text
|
|
450
|
+
funcmod/funcmod.mjs → api.funcmod() (callable function)
|
|
451
|
+
multi_func/
|
|
452
|
+
├── alpha.mjs → api.multi_func.alpha()
|
|
453
|
+
└── beta.cjs → api.multi_func.beta() (CJS callable)
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
### Mixed ESM/CJS Modules
|
|
457
|
+
|
|
458
|
+
```text
|
|
459
|
+
interop/
|
|
460
|
+
├── esm-module.mjs → api.interop.esmModule
|
|
461
|
+
├── cjs-module.cjs → api.interop.cjsModule
|
|
462
|
+
└── mixed.mjs → api.interop.mixed (calls both ESM and CJS)
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
### Hybrid Export Patterns
|
|
466
|
+
|
|
467
|
+
```text
|
|
468
|
+
exportDefault/exportDefault.mjs → api.exportDefault() (callable with methods)
|
|
469
|
+
objectDefaultMethod/ → api.objectDefaultMethod() (object with default)
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
### Nested Structure
|
|
473
|
+
|
|
474
|
+
```text
|
|
475
|
+
nested/
|
|
476
|
+
└── date/
|
|
477
|
+
├── date.mjs → api.nested.date
|
|
478
|
+
└── util.cjs → api.nested.dateUtil
|
|
479
|
+
advanced/
|
|
480
|
+
├── selfObject/ → api.advanced.selfObject
|
|
481
|
+
└── nest*/ → Various nesting examples
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
### Utility Modules
|
|
485
|
+
|
|
486
|
+
```text
|
|
487
|
+
util/
|
|
488
|
+
├── controller.mjs → api.util.controller
|
|
489
|
+
├── extract.cjs → api.util.extract (CJS utility)
|
|
490
|
+
└── url/
|
|
491
|
+
├── parser.mjs → api.util.url.parser
|
|
492
|
+
└── builder.cjs → api.util.url.builder (mixed)
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
### Smart Function Naming Examples
|
|
496
|
+
|
|
497
|
+
```text
|
|
498
|
+
task/auto-ip.mjs (exports autoIP) → api.task.autoIP (preserves function name)
|
|
499
|
+
util/parseJSON.mjs → api.util.parseJSON (preserves JSON casing)
|
|
500
|
+
api/getHTTPStatus.mjs → api.api.getHTTPStatus (preserves HTTP casing)
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
## 🔀 How Slothlet Works: Loading Modes Explained
|
|
504
|
+
|
|
505
|
+
```mermaid
|
|
506
|
+
flowchart TD
|
|
507
|
+
MODULEFOLDERS --> SLOTHLET
|
|
508
|
+
SLOTHLET --> CHOOSEMODE
|
|
509
|
+
|
|
510
|
+
CHOOSEMODE --> LAZY
|
|
511
|
+
CHOOSEMODE --> EAGER
|
|
512
|
+
|
|
513
|
+
subgraph EAGER ["⚡ Eager Mode"]
|
|
514
|
+
direction TB
|
|
515
|
+
EAGER0 ~~~ EAGER1
|
|
516
|
+
EAGER2 ~~~ EAGER3
|
|
517
|
+
|
|
518
|
+
EAGER0@{ shape: braces, label: "📥 All modules loaded immediately" }
|
|
519
|
+
EAGER1@{ shape: braces, label: "✅ API methods available right away" }
|
|
520
|
+
EAGER2@{ shape: braces, label: "🔄 Function calls behave as originally defined" }
|
|
521
|
+
EAGER3@{ shape: braces, label: "📞 Sync stays sync: api.math.add(2,3)<br/>🔄 Async stays async: await api.async.process()" }
|
|
522
|
+
end
|
|
523
|
+
|
|
524
|
+
subgraph LAZY ["💤 Lazy Mode"]
|
|
525
|
+
direction TB
|
|
526
|
+
LAZY0 ~~~ LAZY1
|
|
527
|
+
LAZY2 ~~~ LAZY3
|
|
528
|
+
LAZY4 ~~~ LAZY5
|
|
529
|
+
|
|
530
|
+
LAZY0@{ shape: braces, label: "📦 Modules not loaded yet" }
|
|
531
|
+
LAZY1@{ shape: braces, label: "🎭 API methods are placeholders/proxies" }
|
|
532
|
+
LAZY2@{ shape: braces, label: "📞 First call triggers materialization" }
|
|
533
|
+
LAZY3@{ shape: braces, label: "⏳ All calls must be awaited<br/>await api.math.add(2,3)" }
|
|
534
|
+
LAZY4@{ shape: braces, label: "💾 Module stays loaded after materialization<br/>Copy-left materialization" }
|
|
535
|
+
LAZY5@{ shape: braces, label: "🚀 Subsequent calls nearly as fast as eager mode" }
|
|
536
|
+
end
|
|
537
|
+
|
|
538
|
+
subgraph EAGERCALL ["⚡ Eager Mode Calls"]
|
|
539
|
+
direction TB
|
|
540
|
+
end
|
|
541
|
+
|
|
542
|
+
subgraph LAZYCALL ["💤 Lazy Mode Calls"]
|
|
543
|
+
direction TB
|
|
544
|
+
LAZYCALL0 --> LAZYCALL2
|
|
545
|
+
|
|
546
|
+
LAZYCALL0@{ shape: rounded, label: "📞 First call" }
|
|
547
|
+
LAZYCALL1@{ shape: rounded, label: "🔁 Sequential calls" }
|
|
548
|
+
LAZYCALL2@{ shape: rounded, label: "🧩 Materialize" }
|
|
549
|
+
end
|
|
550
|
+
|
|
551
|
+
EAGER --> READYTOUSE
|
|
552
|
+
LAZY --> READYTOUSE
|
|
553
|
+
|
|
554
|
+
READYTOUSE --> CALL
|
|
555
|
+
CALL -.-> EAGERCALL
|
|
556
|
+
CALL -.-> LAZYCALL
|
|
557
|
+
|
|
558
|
+
EAGERCALL --> MATERIALIZEDFUNCTION
|
|
559
|
+
LAZYCALL1 --> MATERIALIZEDFUNCTION
|
|
560
|
+
LAZYCALL2 --> MATERIALIZEDFUNCTION
|
|
561
|
+
|
|
562
|
+
READYTOUSE@{ shape: rounded, label: "🎯 Ready to Use" }
|
|
563
|
+
MATERIALIZEDFUNCTION@{ shape: rounded, label: "✅ Materialized method/property" }
|
|
564
|
+
CALL@{ shape: trap-b, label: "📞 Call" }
|
|
565
|
+
|
|
566
|
+
%% Notes as unattached nodes with braces shape
|
|
567
|
+
subgraph ALWAYS ["✨ Extras Always On"]
|
|
568
|
+
direction TB
|
|
569
|
+
ALWAYS0 ~~~ ALWAYS1
|
|
570
|
+
ALWAYS1 ~~~ ALWAYS2
|
|
571
|
+
|
|
572
|
+
ALWAYS0@{ shape: rounded, label: "🔗 Live Bindings ALS<br/>Per-instance context isolation" }
|
|
573
|
+
ALWAYS1@{ shape: rounded, label: "🏷️ Smart Naming & Flattening<br/>math/math.mjs → api.math" }
|
|
574
|
+
ALWAYS2@{ shape: rounded, label: "🔄 Mixed Module Support<br/>Seamlessly mix .mjs and .cjs" }
|
|
575
|
+
end
|
|
576
|
+
|
|
577
|
+
MODULEFOLDERS@{ shape: st-rect, label: "📁 Modules Folder<br/>.mjs and/or .cjs files<br/>math.mjs, string.cjs, async.mjs" }
|
|
578
|
+
SLOTHLET@{ shape: rounded, label: "🔧 Call slothlet(options)" }
|
|
579
|
+
CHOOSEMODE@{ shape: diamond, label: "Choose Mode<br/>in options" }
|
|
580
|
+
|
|
581
|
+
style EAGER0 stroke:#9BC66B,color:#9BC66B,opacity:0.5
|
|
582
|
+
style EAGER1 stroke:#9BC66B,color:#9BC66B,opacity:0.5
|
|
583
|
+
style EAGER2 stroke:#9BC66B,color:#9BC66B,opacity:0.5
|
|
584
|
+
style EAGER3 stroke:#9BC66B,color:#9BC66B,opacity:0.5
|
|
585
|
+
|
|
586
|
+
style LAZY0 stroke:#9BC66B,color:#9BC66B,opacity:0.5
|
|
587
|
+
style LAZY1 stroke:#9BC66B,color:#9BC66B,opacity:0.5
|
|
588
|
+
style LAZY2 stroke:#9BC66B,color:#9BC66B,opacity:0.5
|
|
589
|
+
style LAZY3 stroke:#9BC66B,color:#9BC66B,opacity:0.5
|
|
590
|
+
style LAZY4 stroke:#9BC66B,color:#9BC66B,opacity:0.5
|
|
591
|
+
style LAZY5 stroke:#9BC66B,color:#9BC66B,opacity:0.5
|
|
592
|
+
|
|
593
|
+
%% Slothlet brand colors - #9BC66B primary on dark theme
|
|
594
|
+
style MODULEFOLDERS fill:#1a1a1a,stroke:#9BC66B,stroke-width:2px,color:#9BC66B,opacity:0.5
|
|
595
|
+
style SLOTHLET fill:#1a1a1a,stroke:#9BC66B,stroke-width:2px,color:#9BC66B,opacity:0.5
|
|
596
|
+
style CHOOSEMODE fill:#1a1a1a,stroke:#9BC66B,stroke-width:2px,color:#9BC66B,opacity:0.5
|
|
597
|
+
style READYTOUSE fill:#1a1a1a,stroke:#9BC66B,stroke-width:2px,color:#9BC66B,opacity:0.5
|
|
598
|
+
style CALL fill:#1a1a1a,stroke:#9BC66B,stroke-width:2px,color:#9BC66B,opacity:0.5
|
|
599
|
+
style MATERIALIZEDFUNCTION fill:#1a1a1a,stroke:#9BC66B,stroke-width:2px,color:#9BC66B,opacity:0.5
|
|
600
|
+
|
|
601
|
+
%% Eager mode - primary green
|
|
602
|
+
style EAGER fill:#0d1a0d,stroke:#9BC66B,stroke-width:3px,color:#9BC66B,opacity:0.5
|
|
603
|
+
style EAGERCALL fill:#0d1a0d,stroke:#9BC66B,stroke-width:2px,color:#9BC66B,opacity:0.5
|
|
604
|
+
|
|
605
|
+
%% Lazy mode - lighter green tint
|
|
606
|
+
style LAZY fill:#0d1a0d,stroke:#B8D982,stroke-width:3px,color:#B8D982,opacity:0.5
|
|
607
|
+
style LAZYCALL fill:#0d1a0d,stroke:#B8D982,stroke-width:2px,color:#B8D982,opacity:0.5
|
|
608
|
+
style LAZYCALL0 fill:#1a1a1a,stroke:#B8D982,stroke-width:2px,color:#B8D982,opacity:0.5
|
|
609
|
+
style LAZYCALL1 fill:#1a1a1a,stroke:#B8D982,stroke-width:2px,color:#B8D982,opacity:0.5
|
|
610
|
+
style LAZYCALL2 fill:#1a1a1a,stroke:#B8D982,stroke-width:2px,color:#B8D982,opacity:0.5
|
|
611
|
+
|
|
612
|
+
%% Always available - accent green
|
|
613
|
+
style ALWAYS fill:#0d1a0d,stroke:#7FA94F,stroke-width:3px,color:#7FA94F,opacity:0.5
|
|
614
|
+
style ALWAYS0 fill:#1a1a1a,stroke:#7FA94F,stroke-width:1px,color:#7FA94F,opacity:0.5
|
|
615
|
+
style ALWAYS1 fill:#1a1a1a,stroke:#7FA94F,stroke-width:1px,color:#7FA94F,opacity:0.5
|
|
616
|
+
style ALWAYS2 fill:#1a1a1a,stroke:#7FA94F,stroke-width:1px,color:#7FA94F,opacity:0.5
|
|
617
|
+
|
|
618
|
+
%% Arrow styling
|
|
619
|
+
linkStyle default stroke:#9BC66B,stroke-width:3px,opacity:0.5
|
|
620
|
+
linkStyle 4,5,6,7,8,18,19 stroke-width:0px
|
|
621
|
+
```
|
|
622
|
+
|
|
623
|
+
---
|
|
624
|
+
|
|
625
|
+
## 🚀 Performance Modes
|
|
626
|
+
|
|
627
|
+
### Eager Mode (Default - Production Ready)
|
|
628
|
+
|
|
629
|
+
```javascript
|
|
630
|
+
const api = await slothlet({ dir: "./api" }); // lazy: false by default
|
|
631
|
+
|
|
632
|
+
// Functions behave as originally defined - no await needed for sync functions
|
|
633
|
+
const result = api.math.add(2, 3); // Sync function - direct call
|
|
634
|
+
const greeting = api("World"); // Instant if callable
|
|
635
|
+
|
|
636
|
+
// Async functions still need await (as originally defined)
|
|
637
|
+
const asyncResult = await api.async.processData({ data: "test" }); // Original async function
|
|
638
|
+
|
|
639
|
+
// ESM+CJS works seamlessly with native behavior
|
|
640
|
+
const mixed = api.interop.process({ data: "test" }); // Sync or async as defined
|
|
641
|
+
```
|
|
642
|
+
|
|
643
|
+
**Benefits:**
|
|
644
|
+
|
|
645
|
+
- ✅ Fastest function calls (0.36μs average)
|
|
646
|
+
- ✅ Predictable performance
|
|
647
|
+
- ✅ No materialization delays
|
|
648
|
+
- ✅ Functions behave exactly as originally defined (sync stays sync, async stays async)
|
|
649
|
+
- ✅ Optimal for production environments
|
|
650
|
+
|
|
651
|
+
### Lazy Mode with Copy-Left Materialization (Production Ready)
|
|
652
|
+
|
|
653
|
+
```javascript
|
|
654
|
+
const api = await slothlet({ lazy: true, dir: "./api" });
|
|
655
|
+
|
|
656
|
+
// ALL function calls must be awaited in lazy mode (due to materialization)
|
|
657
|
+
const result1 = await api.math.add(2, 3); // First access: ~310μs (materialization)
|
|
658
|
+
const result2 = await api.math.add(5, 7); // Subsequent: ~0.5μs (materialized)
|
|
659
|
+
|
|
660
|
+
// Even originally sync functions need await in lazy mode
|
|
661
|
+
const greeting = await api("World"); // Callable interface also needs await
|
|
662
|
+
const syncResult = await api.string.format("Hello"); // Originally sync, but needs await
|
|
663
|
+
```
|
|
664
|
+
|
|
665
|
+
**Benefits:**
|
|
666
|
+
|
|
667
|
+
- ✅ 4.3x faster startup (564.17μs vs 2.45ms)
|
|
668
|
+
- ✅ Memory efficient (loads only what you use)
|
|
669
|
+
- ✅ Copy-left optimization (once loaded, stays loaded)
|
|
670
|
+
- ✅ Optimal for startup-sensitive applications
|
|
671
|
+
- ⚠️ All function calls require await (regardless of original sync/async nature)
|
|
672
|
+
|
|
673
|
+
**Performance Summary:**
|
|
674
|
+
|
|
675
|
+
> [!TIP]
|
|
676
|
+
> **Choose your loading strategy based on your needs:**
|
|
677
|
+
>
|
|
678
|
+
> - **Startup**: Lazy wins (4.3x faster - 564.17μs vs 2.45ms)
|
|
679
|
+
> - **Function calls**: Eager wins (1.1x faster - 0.65μs vs 0.72μs)
|
|
680
|
+
> - **Memory**: Lazy wins (loads only what you use)
|
|
681
|
+
> - **Predictability**: Eager wins (no materialization delays)
|
|
682
|
+
|
|
683
|
+
---
|
|
684
|
+
|
|
685
|
+
## 🛡 Error Handling
|
|
686
|
+
|
|
687
|
+
> [!NOTE]
|
|
688
|
+
> **Current Error Behavior**: Slothlet currently uses standard JavaScript error handling. Enhanced error handling with module suggestions is planned for v2.1.0 but not yet implemented.
|
|
689
|
+
|
|
690
|
+
**Current behavior:**
|
|
691
|
+
|
|
692
|
+
```javascript
|
|
693
|
+
try {
|
|
694
|
+
console.log(api.nonexistent); // Returns: undefined
|
|
695
|
+
await api.nonexistent.method(); // Throws: "Cannot read properties of undefined (reading 'method')"
|
|
696
|
+
} catch (error) {
|
|
697
|
+
console.error(error.message); // Standard JavaScript error message
|
|
698
|
+
}
|
|
699
|
+
```
|
|
700
|
+
|
|
701
|
+
**Planned Enhanced Error Features (v2.1.0):**
|
|
702
|
+
|
|
703
|
+
> [!TIP]
|
|
704
|
+
> **Coming Soon**: Enhanced error handling with descriptive messages and module suggestions:
|
|
705
|
+
>
|
|
706
|
+
> ```javascript
|
|
707
|
+
> try {
|
|
708
|
+
> await api.nonexistent.method();
|
|
709
|
+
> } catch (error) {
|
|
710
|
+
> console.error(error.message);
|
|
711
|
+
> // Planned: "Module 'nonexistent' not found in './api'. Available modules: math, string, util. Did you mean 'util'?"
|
|
712
|
+
> }
|
|
713
|
+
> ```
|
|
714
|
+
>
|
|
715
|
+
> **Planned Features:**
|
|
716
|
+
>
|
|
717
|
+
> - 🔍 **Module discovery**: Show available modules and suggest alternatives
|
|
718
|
+
> - 📍 **Context information**: Include directory path and configuration details
|
|
719
|
+
> - 🎯 **Actionable suggestions**: Provide specific guidance for resolution
|
|
720
|
+
> - 🚀 **Development mode**: Additional debugging information when debug flag is enabled
|
|
721
|
+
|
|
722
|
+
---
|
|
723
|
+
|
|
724
|
+
## 🔧 Production vs Development Modes
|
|
725
|
+
|
|
726
|
+
### Production Ready ✅
|
|
727
|
+
|
|
728
|
+
- **Eager Mode**: Stable, battle-tested, maximum performance
|
|
729
|
+
- **Lazy Mode**: Production-ready with copy-left optimization
|
|
730
|
+
- **Singleton Mode**: Default mode for standard applications
|
|
731
|
+
- **Mixed Module Loading**: ESM/CJS interoperability fully supported
|
|
732
|
+
|
|
733
|
+
### Development Features 🛠️
|
|
734
|
+
|
|
735
|
+
- **Development Check**: `devcheck.mjs` for environment validation
|
|
736
|
+
- **Debug Mode**: Comprehensive logging via `--slothletdebug` flag or `SLOTHLET_DEBUG=true`
|
|
737
|
+
- **Performance Monitoring**: Built-in timing and performance analysis
|
|
738
|
+
- **Source Detection**: Automatic `src/` vs `dist/` mode detection
|
|
739
|
+
|
|
740
|
+
### Experimental ⚠️
|
|
741
|
+
|
|
742
|
+
> [!WARNING]
|
|
743
|
+
> The following modes are in active development and not recommended for production use:
|
|
744
|
+
>
|
|
745
|
+
> - **Worker Mode**: Thread isolation (in development)
|
|
746
|
+
> - **Fork Mode**: Process isolation (in development)
|
|
747
|
+
> - **Child Mode**: Child process execution (in development)
|
|
748
|
+
> - **VM Mode**: Virtual machine context (in development)
|
|
749
|
+
>
|
|
750
|
+
> The experimental modes are located in `src/lib/engine/` and should not be used in production environments.
|
|
751
|
+
|
|
752
|
+
---
|
|
753
|
+
|
|
754
|
+
## 🌟 Migration from v1.x
|
|
755
|
+
|
|
756
|
+
### Key Changes
|
|
757
|
+
|
|
758
|
+
1. **Import paths**: `@cldmv/slothlet` instead of specific file paths
|
|
759
|
+
2. **Configuration**: New options (`api_mode`, `context`, `reference`)
|
|
760
|
+
3. **Function names**: Enhanced preservation of original capitalization
|
|
761
|
+
4. **Module structure**: Mixed ESM/CJS support
|
|
762
|
+
5. **Live bindings**: New runtime system with AsyncLocalStorage
|
|
763
|
+
|
|
764
|
+
### Migration Steps
|
|
765
|
+
|
|
766
|
+
```javascript
|
|
767
|
+
// v1.3.x - API creation (same pattern as v2.x)
|
|
768
|
+
import slothlet from "@cldmv/slothlet";
|
|
769
|
+
const api = await slothlet({
|
|
770
|
+
dir: "./api",
|
|
771
|
+
lazy: true
|
|
772
|
+
});
|
|
773
|
+
|
|
774
|
+
// v1.3.x - Multiple instances required query strings or withInstanceId()
|
|
775
|
+
const api1 = await slothlet({ dir: "./api?instanceId=alice" });
|
|
776
|
+
const api2 = slothlet.withInstanceId("bob");
|
|
777
|
+
const bobApi = await api2({ dir: "./api" });
|
|
778
|
+
|
|
779
|
+
// v2.0 - Same API creation, but automatic instance isolation
|
|
780
|
+
import slothlet from "@cldmv/slothlet";
|
|
781
|
+
const api = await slothlet({
|
|
782
|
+
dir: "./api",
|
|
783
|
+
lazy: true,
|
|
784
|
+
context: { user: "alice" }, // New: context injection
|
|
785
|
+
api_mode: "auto" // New: API mode control
|
|
786
|
+
});
|
|
787
|
+
|
|
788
|
+
// v2.0 - Multiple instances automatically isolated (no query strings needed)
|
|
789
|
+
const api1 = await slothlet({ dir: "./api", context: { tenant: "alice" } });
|
|
790
|
+
const api2 = await slothlet({ dir: "./api", context: { tenant: "bob" } });
|
|
791
|
+
```
|
|
792
|
+
|
|
793
|
+
### Performance Improvements
|
|
794
|
+
|
|
795
|
+
- **Architectural optimizations** with copy-left materialization and AsyncLocalStorage integration
|
|
796
|
+
- **Zero dependencies** - pure Node.js implementation reduces overhead
|
|
797
|
+
- **Enhanced materialization** with copy-left optimization in lazy mode
|
|
798
|
+
- **Modular design** improves maintainability and potential optimization opportunities
|
|
799
|
+
|
|
800
|
+
---
|
|
801
|
+
|
|
802
|
+
## 🤝 Contributing
|
|
803
|
+
|
|
804
|
+
We welcome contributions! The experimental modes in particular need development and testing. Please:
|
|
805
|
+
|
|
806
|
+
1. **Review the code** in `src/lib/engine/` for experimental features
|
|
807
|
+
2. **Report issues** with detailed reproduction steps
|
|
808
|
+
3. **Submit pull requests** with comprehensive tests
|
|
809
|
+
4. **Provide feedback** on API design and performance
|
|
810
|
+
5. **Documentation improvements** are always appreciated
|
|
811
|
+
|
|
812
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for detailed contribution guidelines.
|
|
813
|
+
|
|
814
|
+
[![Contributors]][contributors_url] [![Sponsor shinrai]][sponsor_url]
|
|
815
|
+
|
|
816
|
+
---
|
|
817
|
+
|
|
818
|
+
## 📊 Performance Analysis
|
|
819
|
+
|
|
820
|
+
For comprehensive performance benchmarks, analysis, and recommendations:
|
|
821
|
+
|
|
822
|
+
**📈 [See PERFORMANCE.md](PERFORMANCE.md)**
|
|
823
|
+
|
|
824
|
+
Key highlights:
|
|
825
|
+
|
|
826
|
+
- Detailed startup vs runtime performance comparison
|
|
827
|
+
- Memory usage analysis by loading mode
|
|
828
|
+
- Materialization cost breakdown by module type
|
|
829
|
+
- Real-world performance recommendations
|
|
830
|
+
|
|
831
|
+
[![CodeFactor]][codefactor_url] [![npms.io score]][npms_url]
|
|
832
|
+
|
|
833
|
+
[![npm unpacked size]][npm_size_url] [![Repo size]][repo_size_url]
|
|
834
|
+
|
|
835
|
+
---
|
|
836
|
+
|
|
837
|
+
## 📚 Documentation
|
|
838
|
+
|
|
839
|
+
- **[API Documentation](docs/API.md)** - Complete API reference with examples
|
|
840
|
+
- **[Performance Analysis](PERFORMANCE.md)** - Detailed benchmarks and recommendations
|
|
841
|
+
- **[Contributing Guide](CONTRIBUTING.md)** - How to contribute to the project
|
|
842
|
+
- **[Security Policy](SECURITY.md)** - Security guidelines and reporting
|
|
843
|
+
- **[Test Documentation](api_tests/)** - Comprehensive test module examples
|
|
844
|
+
|
|
845
|
+
---
|
|
846
|
+
|
|
847
|
+
## 🔗 Links
|
|
848
|
+
|
|
849
|
+
- **npm**: [@cldmv/slothlet](https://www.npmjs.com/package/@cldmv/slothlet)
|
|
850
|
+
- **GitHub**: [CLDMV/slothlet](https://github.com/CLDMV/slothlet)
|
|
851
|
+
- **Issues**: [GitHub Issues](https://github.com/CLDMV/slothlet/issues)
|
|
852
|
+
- **Releases**: [GitHub Releases](https://github.com/CLDMV/slothlet/releases)
|
|
853
|
+
|
|
854
|
+
---
|
|
855
|
+
|
|
856
|
+
## 📄 License
|
|
857
|
+
|
|
858
|
+
[![GitHub license]][github_license_url] [![npm license]][npm_license_url]
|
|
114
859
|
|
|
115
860
|
Apache-2.0 © Shinrai / CLDMV
|
|
861
|
+
|
|
862
|
+
---
|
|
863
|
+
|
|
864
|
+
## 🙏 Acknowledgments
|
|
865
|
+
|
|
866
|
+
Slothlet v2.0 represents a complete architectural rewrite with enterprise-grade features and performance. Special thanks to all contributors who made this comprehensive enhancement possible.
|
|
867
|
+
|
|
868
|
+
**🎉 Welcome to the future of module loading with Slothlet v2.0!**
|
|
869
|
+
|
|
870
|
+
> _Where sophisticated architecture meets blazing performance - slothlet is anything but slow._
|
|
871
|
+
|
|
872
|
+
<!-- [github release]: https://img.shields.io/github/v/release/CLDMV/slothlet?style=for-the-badge&logo=github&logoColor=white&labelColor=181717 -->
|
|
873
|
+
<!-- [github_release_url]: https://github.com/CLDMV/slothlet/releases -->
|
|
874
|
+
|
|
875
|
+
[npm version]: https://img.shields.io/npm/v/%40cldmv%2Fslothlet.svg?style=for-the-badge&logo=npm&logoColor=white&labelColor=CB3837
|
|
876
|
+
[npm_version_url]: https://www.npmjs.com/package/@cldmv/slothlet
|
|
877
|
+
[last commit]: https://img.shields.io/github/last-commit/CLDMV/slothlet?style=for-the-badge&logo=github&logoColor=white&labelColor=181717
|
|
878
|
+
[last_commit_url]: https://github.com/CLDMV/slothlet/commits
|
|
879
|
+
|
|
880
|
+
<!-- [release date]: https://img.shields.io/github/release-date/CLDMV/slothlet?style=for-the-badge&logo=github&logoColor=white&labelColor=181717 -->
|
|
881
|
+
<!-- [release_date_url]: https://github.com/CLDMV/slothlet/releases -->
|
|
882
|
+
|
|
883
|
+
[npm last update]: https://img.shields.io/npm/last-update/%40cldmv%2Fslothlet?style=for-the-badge&logo=npm&logoColor=white&labelColor=CB3837
|
|
884
|
+
[npm_last_update_url]: https://www.npmjs.com/package/@cldmv/slothlet
|
|
885
|
+
[codefactor]: https://img.shields.io/codefactor/grade/github/CLDMV/slothlet?style=for-the-badge&logo=codefactor&logoColor=white&labelColor=F44A6A
|
|
886
|
+
[codefactor_url]: https://www.codefactor.io/repository/github/cldmv/slothlet
|
|
887
|
+
[npms.io score]: https://img.shields.io/npms-io/final-score/%40cldmv%2Fslothlet?style=for-the-badge&logo=npms&logoColor=white&labelColor=0B5D57
|
|
888
|
+
[npms_url]: https://npms.io/search?q=%40cldmv%2Fslothlet
|
|
889
|
+
[npm downloads]: https://img.shields.io/npm/dm/%40cldmv%2Fslothlet.svg?style=for-the-badge&logo=npm&logoColor=white&labelColor=CB3837
|
|
890
|
+
[npm_downloads_url]: https://www.npmjs.com/package/@cldmv/slothlet
|
|
891
|
+
[github downloads]: https://img.shields.io/github/downloads/CLDMV/slothlet/total?style=for-the-badge&logo=github&logoColor=white&labelColor=181717
|
|
892
|
+
[github_downloads_url]: https://github.com/CLDMV/slothlet/releases
|
|
893
|
+
[npm unpacked size]: https://img.shields.io/npm/unpacked-size/%40cldmv%2Fslothlet.svg?style=for-the-badge&logo=npm&logoColor=white&labelColor=CB3837
|
|
894
|
+
[npm_size_url]: https://www.npmjs.com/package/@cldmv/slothlet
|
|
895
|
+
[repo size]: https://img.shields.io/github/repo-size/CLDMV/slothlet?style=for-the-badge&logo=github&logoColor=white&labelColor=181717
|
|
896
|
+
[repo_size_url]: https://github.com/CLDMV/slothlet
|
|
897
|
+
[github license]: https://img.shields.io/github/license/CLDMV/slothlet.svg?style=for-the-badge&logo=github&logoColor=white&labelColor=181717
|
|
898
|
+
[github_license_url]: LICENSE
|
|
899
|
+
[npm license]: https://img.shields.io/npm/l/%40cldmv%2Fslothlet.svg?style=for-the-badge&logo=npm&logoColor=white&labelColor=CB3837
|
|
900
|
+
[npm_license_url]: https://www.npmjs.com/package/@cldmv/slothlet
|
|
901
|
+
[contributors]: https://img.shields.io/github/contributors/CLDMV/slothlet.svg?style=for-the-badge&logo=github&logoColor=white&labelColor=181717
|
|
902
|
+
[contributors_url]: https://github.com/CLDMV/slothlet/graphs/contributors
|
|
903
|
+
[sponsor shinrai]: https://img.shields.io/github/sponsors/shinrai?style=for-the-badge&logo=githubsponsors&logoColor=white&labelColor=EA4AAA&label=Sponsor
|
|
904
|
+
[sponsor_url]: https://github.com/sponsors/shinrai
|