@cldmv/slothlet 3.6.0 โ†’ 3.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # @cldmv/slothlet
2
2
 
3
3
  <div align="center">
4
- <img src="https://github.com/CLDMV/slothlet/raw/HEAD/images/slothlet-logo-v1-horizontal-transparent.png" alt="Slothlet Logo" width="600">
4
+ <img src="https://github.com/CLDMV/slothlet/raw/HEAD/images/slothlet-logo-v1-horizontal-transparent.png" alt="Slothlet Logo" width="600">
5
5
  </div>
6
6
 
7
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.
@@ -37,38 +37,24 @@ v3 rebuilds Slothlet from the inside out with a **Unified Wrapper architecture**
37
37
 
38
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
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)**
40
+ ๐Ÿ“‹ **[See the full v3.0 changelog](./docs/changelog/v3.0.md)** for the architecture rewrite, hook system redesign, i18n layer, background materialization, lifecycle events, collision modes, mutation controls, sanitization improvements, and context isolation upgrades.
53
41
 
54
42
  ---
55
43
 
56
44
  ## โœจ What's New
57
45
 
58
- ### Latest: v3.6.0 (May 2026)
46
+ ### Latest: v3.7.0 (May 2026)
59
47
 
60
- - **`self.slothlet.lockCaller(fn)`** โ€” pins the registering module's caller identity onto a callback. Callbacks stored in plain arrays โ€” a web framework's `addHook` handler, a third-party event registry โ€” never pass through slothlet's `EventEmitter` patch, so they run with whatever module's async context is ambient when they fire. `lockCaller` overrides only the caller identity (request-scoped context stays live), so `self.*` calls and permission rules inside the callback are always attributed to the module that registered it.
61
- - **`self.slothlet.bind(fn)`** โ€” a convenience re-export of Node's `AsyncResource.bind` that freezes the entire async context captured at registration time. Reach for `lockCaller` when you want the caller pinned but request context live, and `bind` when you want the whole context snapshot frozen.
62
- - **Caller identity is now correct for hooks and `run`/`scope` too** โ€” `api.slothlet.hook.on()` auto-pins the registering module's caller identity onto hook handlers by default (opt out with `{ lockCaller: false }`), and `api.slothlet.run()` / `.scope()` callbacks now carry the caller identity through instead of dropping it. A `self.*` call inside a hook or a `run`/`scope` callback is attributed to the module that owns the code.
63
- - [View full v3.6.0 Changelog](./docs/changelog/v3/v3.6.0.md)
48
+ - **Read-level permission gating** โ€” the permission system now checks property _reads_ of data values, not just function _calls_. Until now a module exporting a `Buffer`, `TypedArray`, `Date`, or primitive left that value readable by any other module via `self.something.value` regardless of deny rules โ€” the check fired at invocation, and a data value has no invocation step. Reading a terminal data value off a module API path is now enforced against the rule set exactly like a call, targeting its leaf path. This is **on by default** when `permissions` is configured (set `readGating: false` to opt out) โ€” a `defaultPolicy: "deny"` config will now deny cross-module data reads unless an allow rule covers the path.
49
+ - **Runtime-toggleable** โ€” read gating can be flipped after instance creation via `api.slothlet.permissions.control.readGating(true|false)`. Namespace traversal stays ungated (no per-segment allow rules needed), callable functions remain call-gated, external user-code reads are exempt, and the self-call bypass still applies.
50
+ - [View full v3.7.0 Changelog](./docs/changelog/v3/v3.7.0.md)
64
51
 
65
52
  ### Recent Releases
66
53
 
54
+ - **v3.6.0** (May 2026) โ€” `self.slothlet.lockCaller()` / `bind()` pin caller identity onto callbacks; hooks and `run`/`scope` callbacks keep caller identity ([Changelog](./docs/changelog/v3/v3.6.0.md))
67
55
  - **v3.5.1** (May 2026) โ€” Binary buffers (`Buffer` / `TypedArray` / `DataView`) cross `self` unwrapped; relative imports work from `.ts` / `.mts` modules ([Changelog](./docs/changelog/v3/v3.5.1.md))
68
56
  - **v3.5.0** (May 2026) โ€” TypeScript runtime imports (`self` / `context` / `instanceID`) work from `.ts` / `.mts`; `slothlet typegen` CLI + programmatic API; runtime `self.X = โ€ฆ` assignment now persists ([Changelog](./docs/changelog/v3/v3.5.0.md))
69
57
  - **v3.4.1** (May 2026) โ€” Permission gating for all `api.slothlet.*` routes; metadata hardening against prototype-pollution and circular payloads ([Changelog](./docs/changelog/v3/v3.4.1.md))
70
- - **v3.4.0** (May 2026) โ€” Context-conditional permission rules: optional `condition` field (plain object, function, or array) on rules evaluated against per-request ALS context ([Changelog](./docs/changelog/v3/v3.4.0.md))
71
-
72
58
 
73
59
  ๐Ÿ“š **For complete version history and detailed release notes, see [docs/changelog/](./docs/changelog/) folder.**
74
60
 
@@ -95,12 +81,7 @@ Every feature has been hardened with a comprehensive test suite - over **5,300 t
95
81
  - **Zero dependencies**: Pure Node.js implementation
96
82
  - **Memory efficiency**: Lazy mode loads modules on-demand, eager mode optimizes for predictable behavior
97
83
 
98
- **Mode Selection Guide:**
99
-
100
- - **Eager Mode**: Best for production environments with maximum runtime performance and predictable behavior
101
- - **Lazy Mode**: Best for development and applications with large APIs where startup time matters
102
-
103
- ๐Ÿ“Š **For comprehensive performance benchmarks and analysis, see [docs/PERFORMANCE.md](https://github.com/CLDMV/slothlet/blob/master/docs/PERFORMANCE.md)**
84
+ ๐Ÿ“Š **For comprehensive performance benchmarks and analysis, see [docs/PERFORMANCE.md](./docs/PERFORMANCE.md)**
104
85
 
105
86
  ### ๐ŸŽฃ **Hook System** _(redesigned in v3)_
106
87
 
@@ -113,28 +94,27 @@ Powerful function interceptor system with 4 hook types and three-phase subset or
113
94
 
114
95
  Each hook type supports three ordered execution **subsets**: `"before"` โ†’ `"primary"` (default) โ†’ `"after"`. Pattern matching, priority control, runtime enable/disable, and short-circuit support included.
115
96
 
116
- ๐ŸŽฃ **For complete hook system documentation, see [docs/HOOKS.md](https://github.com/CLDMV/slothlet/blob/master/docs/HOOKS.md)**
97
+ ๐ŸŽฃ **For complete hook system documentation, see [docs/HOOKS.md](./docs/HOOKS.md)**
117
98
 
118
- ### ๐Ÿ” **Permission System** _(new in v3.3)_
99
+ ### ๐Ÿ” **Permission System** _(new in v3.3, read-gated in v3.7)_
119
100
 
120
- Path-based access control for inter-module API calls:
101
+ Path-based access control for inter-module API calls **and** data-value reads (v3.7+):
121
102
 
122
103
  - **Glob pattern rules** โ€” same `*`, `**`, `?`, `{a,b}` syntax as hooks
123
104
  - **Most-specific-wins** โ€” exact patterns override broad globs; tiebreak by registration order
124
105
  - **Self-call bypass** โ€” calls within the same source file always succeed
125
- - **Enforcement before hooks** โ€” denied calls never trigger `before:` hooks or function execution
106
+ - **Read-level gating** _(v3.7)_ โ€” terminal data-value reads (`Buffer`, `TypedArray`, `Date`, `Map`, primitives, โ€ฆ) checked against the rule set; on by default, `readGating: false` to opt out
126
107
  - **Audit events** โ€” `permission:denied`, `permission:allowed`, `permission:default`, `permission:self-bypass`
127
108
  - **Runtime management** โ€” `api.slothlet.permissions.addRule()`, `.removeRule()`, `.self.*`, `.global.*`, `.control.*`
128
- - **Context conditions** _(new in v3.4)_ โ€” optional `condition` field on rules; accepts a plain object (deep nested leaf matching), a function, or an array for OR semantics; evaluated against per-request ALS context; branch allow/deny decisions on runtime values such as role, service level, or domain
109
+ - **Context conditions** _(v3.4)_ โ€” optional `condition` field; accepts a plain object (deep leaf matching), function, or array (OR); evaluated against per-request ALS context
129
110
 
130
- ๐Ÿ” **For complete permission system documentation, see [docs/PERMISSIONS.md](https://github.com/CLDMV/slothlet/blob/master/docs/PERMISSIONS.md)**
111
+ ๐Ÿ” **For complete permission system documentation, see [docs/PERMISSIONS.md](./docs/PERMISSIONS.md)** ยท ๐Ÿ“ **For condition syntax, see [docs/PERMISSIONS-CONDITIONS.md](./docs/PERMISSIONS-CONDITIONS.md)**
131
112
 
132
113
  ### ๐ŸŒ **Full Internationalization** _(new in v3)_
133
114
 
134
- All error messages and debug output are translated. Supported languages:
135
- English ยท Spanish ยท French ยท German ยท Portuguese ยท Italian ยท Japanese ยท Chinese (Simplified) ยท Korean
115
+ All error messages and debug output are translated. Supported languages: English ยท Spanish ยท French ยท German ยท Portuguese ยท Italian ยท Japanese ยท Chinese (Simplified) ยท Korean
136
116
 
137
- Configure via `i18n: { language: "es" }` in your slothlet config.
117
+ Configure via `i18n: { language: "es" }` in your slothlet config. See **[docs/I18N.md](./docs/I18N.md)**.
138
118
 
139
119
  ### ๐Ÿ”„ **Context Propagation**
140
120
 
@@ -145,7 +125,7 @@ Automatic context preservation across all asynchronous boundaries:
145
125
  - **Class instance propagation**: Context preserved in class method calls
146
126
  - **Zero configuration**: Works automatically with TCP servers, HTTP servers, and custom EventEmitters
147
127
 
148
- ๐Ÿ”„ **For context propagation details, see [docs/CONTEXT-PROPAGATION.md](https://github.com/CLDMV/slothlet/blob/master/docs/CONTEXT-PROPAGATION.md)**
128
+ ๐Ÿ”„ **For context propagation details, see [docs/CONTEXT-PROPAGATION.md](./docs/CONTEXT-PROPAGATION.md)**
149
129
 
150
130
  ### ๐Ÿ”ง **Smart API Management**
151
131
 
@@ -154,8 +134,7 @@ Automatic context preservation across all asynchronous boundaries:
154
134
  - **Advanced Sanitization**: Custom naming rules with glob and boundary patterns; `api.slothlet.sanitize()` at runtime
155
135
  - **Hybrid Exports**: Support for callable APIs with methods, default + named exports
156
136
 
157
- ๐Ÿ—๏ธ **For module structure examples, see [docs/MODULE-STRUCTURE.md](https://github.com/CLDMV/slothlet/blob/master/docs/MODULE-STRUCTURE.md)**
158
- ๐Ÿ“ **For API flattening rules, see [docs/API-RULES/API-FLATTENING.md](https://github.com/CLDMV/slothlet/blob/master/docs/API-RULES/API-FLATTENING.md)**
137
+ ๐Ÿ—๏ธ **[Module structure](./docs/MODULE-STRUCTURE.md)** ยท ๐Ÿ“ **[API flattening](./docs/API-RULES/API-FLATTENING.md)** ยท ๐Ÿ”ก **[Sanitization](./docs/SANITIZATION.md)**
159
138
 
160
139
  ### ๐Ÿ”— **Runtime & Context System**
161
140
 
@@ -166,7 +145,7 @@ Automatic context preservation across all asynchronous boundaries:
166
145
 
167
146
  ### ๐Ÿ›  **Developer Experience**
168
147
 
169
- - **TypeScript-Friendly**: Comprehensive JSDoc annotations with auto-generated declarations
148
+ - **TypeScript-Friendly**: Comprehensive JSDoc annotations with auto-generated declarations โ€” see **[docs/TYPESCRIPT.md](./docs/TYPESCRIPT.md)**
170
149
  - **Configurable Debug**: Detailed logging via CLI flags or environment variables
171
150
  - **Multiple Instances**: Parameter-based isolation for complex applications
172
151
  - **Inspectable APIs**: `console.log(api.math)` and logical versioned paths like `console.log(api.auth)` show real module contents instead of proxy internals (v3+)
@@ -190,769 +169,179 @@ npm install @cldmv/slothlet
190
169
 
191
170
  ## ๐Ÿš€ Quick Start
192
171
 
193
- ### ESM (ES Modules)
194
-
195
172
  ```javascript
196
173
  import slothlet from "@cldmv/slothlet";
197
174
 
198
- // Direct usage - eager mode by default
175
+ // Eager mode (default) โ€” functions behave as originally defined
199
176
  const api = await slothlet({
200
177
  dir: "./api",
201
178
  context: { user: "alice" }
202
179
  });
203
180
 
204
- // Eager mode: Functions behave as originally defined
205
- const result = api.math.add(2, 3); // Sync function - no await needed
206
- const asyncResult = await api.async.processData({ data: "async" });
207
-
208
- // Access both ESM and CJS modules seamlessly
209
- const esmResult = api.mathEsm.multiply(4, 5);
210
- const cjsResult = api.mathCjs.divide(10, 2);
181
+ const result = api.math.add(2, 3); // Sync stays sync
182
+ const asyncResult = await api.async.process(); // Async stays async
211
183
  ```
212
184
 
213
- ### CommonJS (CJS)
214
-
215
- ```javascript
216
- const slothlet = require("@cldmv/slothlet");
217
-
218
- const api = await slothlet({
219
- dir: "./api",
220
- context: { env: "production" }
221
- });
222
-
223
- const result = api.math.multiply(4, 5);
224
- const mixedResult = await api.interop.processData({ data: "test" });
225
- ```
185
+ CommonJS works the same way: `const slothlet = require("@cldmv/slothlet")`.
226
186
 
227
- ### Lazy Loading Mode
187
+ **Lazy mode** with copy-left materialization โ€” all calls awaited, ~2.2ร— faster startup:
228
188
 
229
189
  ```javascript
230
- import slothlet from "@cldmv/slothlet";
231
-
232
- // Lazy mode with copy-left materialization
233
- const api = await slothlet({
234
- mode: "lazy",
235
- dir: "./api",
236
- apiDepth: 3
237
- });
238
-
239
- // First access: materialization overhead (~1.45ms average)
240
- const result1 = await api.math.add(2, 3);
241
-
242
- // Subsequent access: materialized function (near-eager performance)
243
- const result2 = await api.math.add(5, 7);
244
- ```
245
-
246
- ### Hook System Example _(v3 API)_
247
-
248
- ```javascript
249
- import slothlet from "@cldmv/slothlet";
250
-
251
- const api = await slothlet({
252
- dir: "./api",
253
- hook: true // Enable hooks - note: "hook" singular (v3)
254
- });
255
-
256
- // Before hook: Modify arguments
257
- api.slothlet.hook.on(
258
- "before:math.add",
259
- ({ path, args }) => {
260
- console.log(`Calling ${path} with args:`, args);
261
- return [args[0] * 2, args[1] * 2]; // Return array to replace arguments
262
- },
263
- { id: "double-args", priority: 100 }
264
- );
265
-
266
- // After hook: Transform result
267
- api.slothlet.hook.on(
268
- "after:math.*",
269
- ({ path, result }) => {
270
- console.log(`${path} returned:`, result);
271
- return result * 10;
272
- },
273
- { id: "scale-result" }
274
- );
275
-
276
- // Always hook: Observe final result (read-only)
277
- api.slothlet.hook.on(
278
- "always:**",
279
- ({ path, result, hasError }) => {
280
- console.log(hasError ? `${path} failed` : `${path} succeeded`);
281
- },
282
- { id: "logger" }
283
- );
284
-
285
- // Error hook: Monitor errors with source tracking
286
- api.slothlet.hook.on(
287
- "error:**",
288
- ({ path, error, source }) => {
289
- console.error(`Error in ${path}:`, error.message);
290
- console.error(`Source: ${source.type}`); // 'before' | 'after' | 'function' | 'always'
291
- },
292
- { id: "error-monitor" }
293
- );
294
-
295
- // Call function - hooks execute automatically
296
- const result = await api.math.add(2, 3);
190
+ const api = await slothlet({ mode: "lazy", dir: "./api" });
191
+ const result = await api.math.add(2, 3); // ALL calls awaited in lazy mode
297
192
  ```
298
193
 
299
- ### Dynamic API Extension _(v3 API)_
300
-
301
- ```javascript
302
- import slothlet from "@cldmv/slothlet";
303
-
304
- const api = await slothlet({ dir: "./api" });
305
-
306
- // Add modules at runtime
307
- await api.slothlet.api.add("plugins", "./plugins-folder");
308
- api.plugins.myPlugin();
309
-
310
- // Create nested API structures
311
- await api.slothlet.api.add("runtime.plugins", "./more-plugins");
312
- api.runtime.plugins.loader();
313
-
314
- // Add with metadata for security/authorization
315
- await api.slothlet.api.add("plugins.trusted", "./trusted-plugins", {
316
- trusted: true,
317
- permissions: ["read", "write", "admin"]
318
- });
319
-
320
- // Remove and reload
321
- await api.slothlet.api.remove("oldModule");
322
- await api.slothlet.api.reload("database.*");
323
- ```
194
+ **Hooks**, **dynamic API extension** (`api.slothlet.api.add/remove/reload`), **per-request context** (`api.slothlet.context.run/scope`), and **lifecycle events** are all covered in the linked technical guides below.
324
195
 
325
196
  ---
326
197
 
327
- ## ๐Ÿ“š Configuration Options
328
-
329
- | Option | Type | Default | Description |
330
- | ------------------------- | --------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
331
- | `dir` | `string` | `"api"` | Directory to load API modules from (absolute or relative path) |
332
- | `mode` | `string` | `"eager"` | Loading mode - `"lazy"` for on-demand loading, `"eager"` for immediate loading |
333
- | `runtime` | `string` | `"async"` | Runtime binding system: `"async"` for AsyncLocalStorage (default), `"live"` for live-bindings |
334
- | `apiDepth` | `number` | `Infinity` | Directory traversal depth - `0` for root only, `Infinity` for all levels |
335
- | `debug` | `boolean` | `false` | Enable verbose logging (also via `--slothletdebug` flag or `SLOTHLET_DEBUG=true` env var) |
336
- | `context` | `object` | `{}` | Context data injected into live-binding (available via `import { context } from "@cldmv/slothlet/runtime"`) |
337
- | `reference` | `object` | `{}` | Reference object merged into API root level |
338
- | `sanitize` | `object` | `{}` | Advanced filename-to-API transformation control with `lowerFirst`, `preserveAllUpper`, `preserveAllLower`, and `rules` (supports exact matches, glob patterns `*json*`, and boundary patterns `**url**`) |
339
- | `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`** |
340
- | `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 |
341
- | `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()` |
342
- | `api.mutations` | `object` | all `true` | Per-operation mutation controls: `{ add: true, remove: true, reload: true, permissions: true }` - set any to `false` to disable |
343
- | `versionDispatcher` | `mixed` | `undefined` | Version routing discriminator: `"version"` (or any string key) looks up that key in the caller's version metadata; a function receives `(allVersions, caller)` and returns a tag or `null`; `undefined` behaves like `"version"` |
344
- | `permissions` | `object` | `undefined` | Permission system config: `{ defaultPolicy: "allow"\|"deny", enabled: true, audit: "default"\|"verbose", rules: [...] }` โ€” rules support optional `condition` field (plain object with deep leaf matching, function, or array of either for OR semantics) for per-request context matching โ€” see [PERMISSIONS.md](./docs/PERMISSIONS.md) |
345
- | `i18n` | `object` | `{}` | Internationalization settings: `{ language: "en" }` - supported: `en`, `es`, `fr`, `de`, `pt`, `it`, `ja`, `zh`, `ko` |
198
+ ## ๐Ÿ“š Configuration
346
199
 
347
- ---
200
+ The most-used options are summarized below. The complete reference โ€” every option, every diagnostic, every deprecated alias โ€” lives in **[docs/CONFIGURATION.md](./docs/CONFIGURATION.md)**.
348
201
 
349
- ## ๐Ÿ”€ How Slothlet Works: Loading Modes Explained
350
-
351
- ```mermaid
352
- flowchart TD
353
- MODULEFOLDERS --> SLOTHLET
354
- SLOTHLET --> CHOOSEMODE
355
-
356
- CHOOSEMODE --> LAZY
357
- CHOOSEMODE --> EAGER
358
-
359
- subgraph EAGER ["โšก Eager Mode"]
360
- direction TB
361
- EAGER0 ~~~ EAGER1
362
- EAGER2 ~~~ EAGER3
363
-
364
- EAGER0@{ shape: braces, label: "๐Ÿ“ฅ All modules loaded immediately" }
365
- EAGER1@{ shape: braces, label: "โœ… API methods available right away" }
366
- EAGER2@{ shape: braces, label: "๐Ÿ”„ Function calls behave as originally defined" }
367
- EAGER3@{ shape: braces, label: "๐Ÿ“ž Sync stays sync: api.math.add(2,3)<br/>๐Ÿ”„ Async stays async: await api.async.process()" }
368
- end
369
-
370
- subgraph LAZY ["๐Ÿ’ค Lazy Mode"]
371
- direction TB
372
- LAZY0 ~~~ LAZY1
373
- LAZY2 ~~~ LAZY3
374
- LAZY4 ~~~ LAZY5
375
-
376
- LAZY0@{ shape: braces, label: "๐Ÿ“ฆ Modules not loaded yet" }
377
- LAZY1@{ shape: braces, label: "๐ŸŽญ API methods are placeholders/proxies" }
378
- LAZY2@{ shape: braces, label: "๐Ÿ“ž First call triggers materialization" }
379
- LAZY3@{ shape: braces, label: "โณ All calls must be awaited<br/>await api.math.add(2,3)" }
380
- LAZY4@{ shape: braces, label: "๐Ÿ’พ Module stays loaded after materialization<br/>Copy-left materialization" }
381
- LAZY5@{ shape: braces, label: "๐Ÿš€ Subsequent calls nearly as fast as eager mode" }
382
- end
383
-
384
- subgraph EAGERCALL ["โšก Eager Mode Calls"]
385
- direction TB
386
- end
387
-
388
- subgraph LAZYCALL ["๐Ÿ’ค Lazy Mode Calls"]
389
- direction TB
390
- LAZYCALL0 --> LAZYCALL2
391
-
392
- LAZYCALL0@{ shape: rounded, label: "๐Ÿ“ž First call" }
393
- LAZYCALL1@{ shape: rounded, label: "๐Ÿ” Sequential calls" }
394
- LAZYCALL2@{ shape: rounded, label: "๐Ÿงฉ Materialize" }
395
- end
396
-
397
- EAGER --> READYTOUSE
398
- LAZY --> READYTOUSE
399
-
400
- READYTOUSE --> CALL
401
- CALL -.-> EAGERCALL
402
- CALL -.-> LAZYCALL
403
-
404
- EAGERCALL --> MATERIALIZEDFUNCTION
405
- LAZYCALL1 --> MATERIALIZEDFUNCTION
406
- LAZYCALL2 --> MATERIALIZEDFUNCTION
407
-
408
- READYTOUSE@{ shape: rounded, label: "๐ŸŽฏ Ready to Use" }
409
- MATERIALIZEDFUNCTION@{ shape: rounded, label: "โœ… Materialized method/property" }
410
- CALL@{ shape: trap-b, label: "๐Ÿ“ž Call" }
411
-
412
- subgraph ALWAYS ["โœจ Extras Always On"]
413
- direction TB
414
- ALWAYS0 ~~~ ALWAYS1
415
- ALWAYS1 ~~~ ALWAYS2
416
-
417
- ALWAYS0@{ shape: rounded, label: "๐Ÿ”— Live Bindings ALS<br/>Per-instance context isolation" }
418
- ALWAYS1@{ shape: rounded, label: "๐Ÿท๏ธ Smart Naming & Flattening<br/>Multiple rules for clean APIs" }
419
- ALWAYS2@{ shape: rounded, label: "๐Ÿ”„ Mixed Module Support<br/>Seamlessly mix .mjs and .cjs" }
420
- end
421
-
422
- MODULEFOLDERS@{ shape: st-rect, label: "๐Ÿ“ Modules Folder<br/>.mjs and/or .cjs files<br/>math.mjs, string.cjs, async.mjs" }
423
- SLOTHLET@{ shape: rounded, label: "๐Ÿ”ง Call slothlet(options)" }
424
- CHOOSEMODE@{ shape: diamond, label: "Choose Mode<br/>in options" }
425
-
426
- style EAGER0 stroke:#9BC66B,color:#9BC66B,opacity:0.5
427
- style EAGER1 stroke:#9BC66B,color:#9BC66B,opacity:0.5
428
- style EAGER2 stroke:#9BC66B,color:#9BC66B,opacity:0.5
429
- style EAGER3 stroke:#9BC66B,color:#9BC66B,opacity:0.5
430
-
431
- style LAZY0 stroke:#9BC66B,color:#9BC66B,opacity:0.5
432
- style LAZY1 stroke:#9BC66B,color:#9BC66B,opacity:0.5
433
- style LAZY2 stroke:#9BC66B,color:#9BC66B,opacity:0.5
434
- style LAZY3 stroke:#9BC66B,color:#9BC66B,opacity:0.5
435
- style LAZY4 stroke:#9BC66B,color:#9BC66B,opacity:0.5
436
- style LAZY5 stroke:#9BC66B,color:#9BC66B,opacity:0.5
437
-
438
- style MODULEFOLDERS fill:#1a1a1a,stroke:#9BC66B,stroke-width:2px,color:#9BC66B,opacity:0.5
439
- style SLOTHLET fill:#1a1a1a,stroke:#9BC66B,stroke-width:2px,color:#9BC66B,opacity:0.5
440
- style CHOOSEMODE fill:#1a1a1a,stroke:#9BC66B,stroke-width:2px,color:#9BC66B,opacity:0.5
441
- style READYTOUSE fill:#1a1a1a,stroke:#9BC66B,stroke-width:2px,color:#9BC66B,opacity:0.5
442
- style CALL fill:#1a1a1a,stroke:#9BC66B,stroke-width:2px,color:#9BC66B,opacity:0.5
443
- style MATERIALIZEDFUNCTION fill:#1a1a1a,stroke:#9BC66B,stroke-width:2px,color:#9BC66B,opacity:0.5
444
-
445
- style EAGER fill:#0d1a0d,stroke:#9BC66B,stroke-width:3px,color:#9BC66B,opacity:0.5
446
- style EAGERCALL fill:#0d1a0d,stroke:#9BC66B,stroke-width:2px,color:#9BC66B,opacity:0.5
447
-
448
- style LAZY fill:#0d1a0d,stroke:#B8D982,stroke-width:3px,color:#B8D982,opacity:0.5
449
- style LAZYCALL fill:#0d1a0d,stroke:#B8D982,stroke-width:2px,color:#B8D982,opacity:0.5
450
- style LAZYCALL0 fill:#1a1a1a,stroke:#B8D982,stroke-width:2px,color:#B8D982,opacity:0.5
451
- style LAZYCALL1 fill:#1a1a1a,stroke:#B8D982,stroke-width:2px,color:#B8D982,opacity:0.5
452
- style LAZYCALL2 fill:#1a1a1a,stroke:#B8D982,stroke-width:2px,color:#B8D982,opacity:0.5
453
-
454
- style ALWAYS fill:#0d1a0d,stroke:#7FA94F,stroke-width:3px,color:#7FA94F,opacity:0.5
455
- style ALWAYS0 fill:#1a1a1a,stroke:#7FA94F,stroke-width:1px,color:#7FA94F,opacity:0.5
456
- style ALWAYS1 fill:#1a1a1a,stroke:#7FA94F,stroke-width:1px,color:#7FA94F,opacity:0.5
457
- style ALWAYS2 fill:#1a1a1a,stroke:#7FA94F,stroke-width:1px,color:#7FA94F,opacity:0.5
458
-
459
- linkStyle default stroke:#9BC66B,stroke-width:3px,opacity:0.5
460
- linkStyle 4,5,6,7,8,18,19 stroke-width:0px
461
- ```
462
-
463
- ---
202
+ | Option | Type | Default | Description |
203
+ | ------------- | -------- | ----------- | ---------------------------------------------------------------------------------- |
204
+ | `dir` | `string` | `"api"` | Directory to load API modules from |
205
+ | `mode` | `string` | `"eager"` | `"eager"` (load upfront) or `"lazy"` (on-demand with copy-left materialization) |
206
+ | `runtime` | `string` | `"async"` | `"async"` (AsyncLocalStorage) or `"live"` (live-bindings) |
207
+ | `context` | `object` | `{}` | Per-request context โ€” read via `import { context } from "@cldmv/slothlet/runtime"` |
208
+ | `hook` | `mixed` | `false` | Enable hooks; see **[HOOKS.md](./docs/HOOKS.md)** |
209
+ | `permissions` | `object` | `undefined` | Path-based access control; see **[PERMISSIONS.md](./docs/PERMISSIONS.md)** |
210
+ | `i18n` | `object` | `{}` | Language for translated error/debug messages โ€” see **[I18N.md](./docs/I18N.md)** |
464
211
 
465
- ## ๐Ÿš€ Performance Modes
212
+ Also configurable: `apiDepth`, `debug`, `reference`, `sanitize`, `backgroundMaterialize`, `api.collision`, `api.mutations`, `versionDispatcher`, `typescript`, plus diagnostics and lifecycle internals. All documented in **[CONFIGURATION.md](./docs/CONFIGURATION.md)**.
466
213
 
467
- ### Eager Mode (Default - Production Ready)
468
-
469
- **Best for:** Production environments, maximum runtime performance, predictable behavior
470
-
471
- ```javascript
472
- const api = await slothlet({ dir: "./api" }); // mode: "eager" by default
473
-
474
- // Functions behave as originally defined
475
- const result = api.math.add(2, 3); // Sync - no await needed
476
- const asyncResult = await api.async.processData({ data: "test" }); // Async needs await
477
- ```
478
-
479
- **Benefits:**
480
-
481
- - โœ… Fast function calls (9.46ฮผs average - within 6% of lazy mode)
482
- - โœ… Predictable performance (no materialization delays)
483
- - โœ… Functions behave exactly as originally defined
484
-
485
- ### Lazy Mode with Copy-Left Materialization (Production Ready)
486
-
487
- **Best for:** Startup-sensitive applications, memory efficiency, loading only what you use
488
-
489
- ```javascript
490
- const api = await slothlet({ mode: "lazy", dir: "./api" });
491
-
492
- // ALL calls must be awaited (materialization process)
493
- const result1 = await api.math.add(2, 3); // First: ~538ฮผs avg (materialization)
494
- const result2 = await api.math.add(5, 7); // Subsequent: ~10ฮผs (materialized)
495
- ```
496
-
497
- **Benefits:**
498
-
499
- - โœ… 2.2x faster startup (15.41ms vs 34.28ms)
500
- - โœ… Equal function call performance (9.99ฮผs vs 9.46ฮผs eager - within 6% measurement noise)
501
- - โœ… Memory efficient (loads only what you use)
502
- - โœ… Copy-left optimization (once loaded, stays loaded)
214
+ ---
503
215
 
504
- ### Lazy Mode with Background Materialization _(new in v3)_
216
+ ## ๐Ÿ”€ Loading Modes
505
217
 
506
- **Best for:** Lazy startup performance with eager runtime performance - pre-warm everything in the background
218
+ | Mode | Startup | Function calls | Best for |
219
+ | -------------------------------------- | -------------- | --------------------------------------------- | --------------------------------------------------- |
220
+ | **Eager** (default) | Loads upfront | Sync stays sync, async stays async | Production, predictable performance |
221
+ | **Lazy** | 2.2ร— faster | All calls awaited; materialized on first use | Large APIs, startup-sensitive apps |
222
+ | **Lazy + `backgroundMaterialize`** | 2.2ร— faster | Pre-warmed by background loader | Best of both โ€” lazy startup, eager runtime |
507
223
 
508
224
  ```javascript
509
- const api = await slothlet({
510
- mode: "lazy",
511
- dir: "./api",
512
- backgroundMaterialize: true
513
- });
514
-
515
- // Subscribe to completion
516
- api.slothlet.lifecycle.on("materialized:complete", (data) => {
517
- console.log(`${data.total} modules materialized`);
518
- });
519
-
520
- // Or await all modules to be ready before serving traffic
521
- await api.slothlet.materialize.wait();
522
-
523
- // Check progress at any time
524
- const stats = api.slothlet.materialize.get();
525
- // { total, materialized, remaining, percentage }
225
+ // Lazy + background materialization
226
+ const api = await slothlet({ mode: "lazy", dir: "./api", backgroundMaterialize: true });
227
+ api.slothlet.lifecycle.on("materialized:complete", ({ total }) => console.log(`${total} modules ready`));
228
+ await api.slothlet.materialize.wait(); // optional: gate traffic on ready
526
229
  ```
527
230
 
528
- > [!TIP]
529
- > **Choose your strategy:**
530
- >
531
- > - **Startup-sensitive?** โ†’ Lazy mode (2.2x faster startup)
532
- > - **Call-intensive?** โ†’ Either mode (function calls essentially equal after materialization)
533
- > - **Need predictability?** โ†’ Eager mode (no materialization delays)
534
- > - **Large API, use subset?** โ†’ Lazy mode (memory efficient)
535
- > - **Want lazy startup + eager runtime?** โ†’ Lazy mode + `backgroundMaterialize: true`
231
+ ๐Ÿ“Š **Benchmarks & analysis: [docs/PERFORMANCE.md](./docs/PERFORMANCE.md)** ยท ๐Ÿ”€ **Visual pipeline diagram: [docs/MODULE-STRUCTURE.md#loading-pipeline-overview](./docs/MODULE-STRUCTURE.md#loading-pipeline-overview)** ยท โšก **Lifecycle events: [docs/LIFECYCLE.md](./docs/LIFECYCLE.md)**
536
232
 
537
233
  ---
538
234
 
539
- ## ๐ŸŽฃ Hook System _(v3)_
235
+ ## ๐ŸŽฃ Hooks
540
236
 
541
- ### Hook Configuration
237
+ Four hook types (`before`, `after`, `always`, `error`) with three-phase subset ordering (`"before"` โ†’ `"primary"` โ†’ `"after"`), pattern matching, priority, and runtime enable/disable.
542
238
 
543
- ```js
544
- // Simple enable (default pattern "**")
239
+ ```javascript
545
240
  const api = await slothlet({ dir: "./api", hook: true });
546
241
 
547
- // Enable with default pattern filter
548
- const api = await slothlet({ dir: "./api", hook: "database.*" });
549
-
550
- // Full configuration
551
- const api = await slothlet({
552
- dir: "./api",
553
- hook: {
554
- enabled: true,
555
- pattern: "**",
556
- suppressErrors: false // true = errors suppressed (returns undefined instead of throwing)
557
- }
558
- });
559
- ```
560
-
561
- ### Hook Types
562
-
563
- - **`before`** - Executes before the function. Can modify arguments or short-circuit. **Must be synchronous.**
564
- - **`after`** - Executes after successful completion. Can transform the return value.
565
- - **`always`** - Read-only observer. Always executes (even on short-circuit). Return value ignored.
566
- - **`error`** - Executes only when an error occurs. Receives error with source tracking.
567
-
568
- ### Basic Usage
569
-
570
- The `hook.on(typePattern, handler, options)` signature uses `"type:pattern"` as the first argument:
571
-
572
- ```js
573
- // Before hook - modify arguments
574
- api.slothlet.hook.on(
575
- "before:math.add",
576
- ({ path, args }) => {
577
- return [args[0] * 2, args[1] * 2]; // Return array to replace arguments
578
- // Return non-array non-undefined to short-circuit (skip function)
579
- // Return undefined to continue with original args
580
- },
581
- { id: "double-args", priority: 100 }
582
- );
583
-
584
- // After hook - transform result
585
- api.slothlet.hook.on(
586
- "after:math.*",
587
- ({ path, result }) => {
588
- return result * 10; // Return value replaces result; undefined = no change
589
- },
590
- { id: "scale-result" }
591
- );
592
-
593
- // Always hook - observe (read-only)
594
- api.slothlet.hook.on(
595
- "always:**",
596
- ({ path, result, hasError, errors }) => {
597
- if (hasError) console.error(`${path} failed:`, errors);
598
- else console.log(`${path} returned:`, result);
599
- // Return value is ignored
600
- },
601
- { id: "logger" }
602
- );
603
-
604
- // Error hook - monitor failures
605
- api.slothlet.hook.on(
606
- "error:**",
607
- ({ path, error, source }) => {
608
- // source.type: "before" | "after" | "always" | "function"
609
- console.error(`Error in ${path} (from ${source.type}):`, error.message);
610
- },
611
- { id: "error-monitor" }
612
- );
613
- ```
242
+ api.slothlet.hook.on("before:math.add", ({ args }) => [args[0] * 2, args[1] * 2], { id: "double" });
243
+ api.slothlet.hook.on("after:math.*", ({ result }) => result * 10, { id: "scale" });
244
+ api.slothlet.hook.on("always:**", ({ path, hasError }) => console.log(path, hasError));
245
+ api.slothlet.hook.on("error:**", ({ path, error, source }) => console.error(path, source.type, error));
614
246
 
615
- ### Hook Subsets _(new in v3)_
616
-
617
- Each hook type has three ordered execution phases:
618
-
619
- | Subset | Order | Typical use |
620
- |---|---|---|
621
- | `"before"` | First | Auth checks, security validation |
622
- | `"primary"` | Middle (default) | Main hook logic |
623
- | `"after"` | Last | Audit trails, cleanup |
624
-
625
- ```js
626
- // Auth check runs first - always
627
- api.slothlet.hook.on(
628
- "before:protected.*",
629
- ({ ctx }) => { if (!ctx.user) throw new Error("Unauthorized"); },
630
- { id: "auth", subset: "before", priority: 2000 }
631
- );
632
-
633
- // Main validation logic - default subset
634
- api.slothlet.hook.on(
635
- "before:protected.*",
636
- ({ args }) => { /* validate */ },
637
- { id: "validate" } // subset: "primary" by default
638
- );
639
-
640
- // Audit log always runs last
641
- api.slothlet.hook.on(
642
- "after:protected.*",
643
- ({ path, result }) => { /* log */ },
644
- { id: "audit", subset: "after" }
645
- );
247
+ const out = await api.math.add(2, 3); // hooks fire automatically
646
248
  ```
647
249
 
648
- ### Pattern Matching
649
-
650
- | Syntax | Description | Example |
651
- |---|---|---|
652
- | `exact.path` | Exact match | `"before:math.add"` |
653
- | `namespace.*` | All functions in namespace | `"after:math.*"` |
654
- | `*.funcName` | Function name across namespaces | `"always:*.add"` |
655
- | `**` | All functions | `"error:**"` |
656
- | `{a,b}` | Brace expansion | `"before:{math,utils}.*"` |
657
- | `!pattern` | Negation | `"before:!internal.*"` |
658
-
659
- ### Hook Management
660
-
661
- ```js
662
- // Remove by ID
663
- api.slothlet.hook.remove({ id: "my-hook" });
664
- api.slothlet.hook.off("my-hook"); // alias
665
-
666
- // Remove by filter
667
- api.slothlet.hook.remove({ type: "before", pattern: "math.*" });
668
-
669
- // Remove all
670
- api.slothlet.hook.clear();
671
-
672
- // List hooks
673
- const all = api.slothlet.hook.list();
674
- const active = api.slothlet.hook.list({ enabled: true });
675
-
676
- // Enable / disable without unregistering
677
- api.slothlet.hook.disable();
678
- api.slothlet.hook.disable({ pattern: "math.*" });
679
- api.slothlet.hook.enable();
680
- api.slothlet.hook.enable({ type: "before" });
681
- ```
250
+ ๐ŸŽฃ **Configuration, all four types, subsets, pattern syntax, management API: [docs/HOOKS.md](./docs/HOOKS.md)**
682
251
 
683
252
  ---
684
253
 
685
- ## ๐Ÿ”„ Per-Request Context _(v3 API)_
686
-
687
- ```js
688
- const api = await slothlet({
689
- dir: "./api",
690
- context: { appName: "MyApp", version: "3.0" }
691
- });
254
+ ## ๐Ÿ”„ Per-Request Context
692
255
 
693
- // run() - execute a function inside a scoped context
256
+ ```javascript
257
+ // Scoped context for a single call
694
258
  await api.slothlet.context.run({ userId: "alice", role: "admin" }, async () => {
695
- // Inside this scope: context = { appName, version, userId, role }
696
259
  await api.database.query();
697
260
  await api.audit.log();
698
261
  });
699
262
 
700
- // scope() - return a new API object with merged context
701
- const scopedApi = api.slothlet.context.scope({ userId: "bob" });
702
- await scopedApi.database.query(); // context includes userId: "bob"
703
-
704
- // Deep merge strategy
705
- await api.slothlet.context.run(
706
- { nested: { prop: "value" } },
707
- handler,
708
- { mergeStrategy: "deep" }
709
- );
263
+ // Derived API with merged context
264
+ const scoped = api.slothlet.context.scope({ userId: "bob" });
265
+ await scoped.database.query();
710
266
  ```
711
267
 
712
- ### Automatic EventEmitter Context Propagation
713
-
714
- Context propagates automatically through EventEmitter callbacks:
715
-
716
- ```js
717
- import net from "net";
718
- import { context } from "@cldmv/slothlet/runtime";
719
-
720
- export const server = {
721
- async start() {
722
- const tcpServer = net.createServer((socket) => {
723
- console.log(`User ${context.userId} connected`);
724
-
725
- socket.on("data", (data) => {
726
- // Context preserved in all nested callbacks
727
- console.log(`Data from ${context.userId}: ${data}`);
728
- });
729
- });
730
- tcpServer.listen(3000);
731
- }
732
- };
733
- ```
268
+ Context propagates automatically through `EventEmitter` callbacks (TCP/HTTP servers, custom emitters), class methods, and every async boundary. Inside modules: `import { context, instanceID } from "@cldmv/slothlet/runtime"`.
734
269
 
735
- > ๐Ÿ“– See [`docs/CONTEXT-PROPAGATION.md`](docs/CONTEXT-PROPAGATION.md)
270
+ ๐Ÿ”„ **Full reference, isolation guarantees, merge strategies, TCP/HTTP examples: [docs/CONTEXT-PROPAGATION.md](./docs/CONTEXT-PROPAGATION.md)**
736
271
 
737
272
  ---
738
273
 
739
- ## ๐Ÿท๏ธ Metadata System
740
-
741
- Tag API paths with metadata for authorization, auditing, and security.
742
-
743
- ```js
744
- // Attach metadata when loading
745
- await api.slothlet.api.add("plugins/trusted", "./trusted-dir", {
746
- metadata: { trusted: true, securityLevel: "high" }
747
- });
748
-
749
- // Set metadata at runtime
750
- api.slothlet.metadata.set("plugins.trusted.someFunc", { version: 2 });
751
- api.slothlet.metadata.setGlobal({ environment: "production" });
752
- api.slothlet.metadata.setFor("plugins/trusted", { owner: "core-team" });
753
- api.slothlet.metadata.remove("plugins.old.func");
754
- ```
755
-
756
- ๐Ÿ”’ **For complete metadata documentation, see [docs/METADATA.md](https://github.com/CLDMV/slothlet/blob/master/docs/METADATA.md)**
757
-
758
- ---
759
-
760
- ## ๐Ÿ” Hot Reload / Dynamic API Management _(v3 API)_
761
-
762
- ```js
763
- // Add new modules at runtime
764
- await api.slothlet.api.add("newModule", "./new-module-path");
765
- await api.slothlet.api.add("plugins", "./plugins", { collision: "merge" });
766
-
767
- // Remove modules
768
- await api.slothlet.api.remove("oldModule");
769
-
770
- // Reload specific path or all modules
771
- await api.slothlet.api.reload("database.*");
772
- await api.slothlet.api.reload("plugins.auth");
773
- ```
774
-
775
- > **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.
274
+ ## ๐Ÿ” Hot Reload & Dynamic API
776
275
 
777
- ### Collision Modes _(new in v3)_
778
-
779
- Control what happens when a loaded path already exists:
780
-
781
- ```js
782
- const api = await slothlet({
783
- dir: "./api",
784
- api: {
785
- collision: {
786
- initial: "merge", // During initial load()
787
- api: "skip" // During api.slothlet.api.add()
788
- }
789
- }
790
- });
276
+ ```javascript
277
+ await api.slothlet.api.add("plugins", "./plugins-folder"); // add at runtime
278
+ await api.slothlet.api.add("plugins.trusted", "./trusted", { metadata: { trusted: true } });
279
+ await api.slothlet.api.remove("oldModule"); // remove
280
+ await api.slothlet.api.reload("database.*"); // hot-reload
791
281
  ```
792
282
 
793
- | Mode | Behavior |
794
- |---|---|
795
- | `"overwrite"` | Replace existing (default) |
796
- | `"merge"` | Deep-merge new into existing |
797
- | `"skip"` | Keep existing, ignore new |
798
- | `"throw"` | Throw an error on conflict |
799
-
800
- ### Mutation Controls _(new in v3)_
283
+ Collision modes (`merge` / `skip` / `overwrite` / `throw`) โ€” independently configurable for initial load vs runtime `add()`. Mutation controls let you disable `add` / `remove` / `reload` in production. Eager vs lazy reload semantics differ (eager merges into the live wrapper; lazy resets to an unmaterialized proxy).
801
284
 
802
- Restrict which API operations are permitted:
803
-
804
- ```js
805
- const api = await slothlet({
806
- dir: "./api",
807
- api: {
808
- mutations: {
809
- add: true,
810
- remove: false, // Prevent removal in production
811
- reload: false // Prevent reload in production
812
- }
813
- }
814
- });
815
- ```
285
+ ๐Ÿ” **Full reference: [docs/RELOAD.md](./docs/RELOAD.md)** ยท ๐Ÿท๏ธ **Metadata system: [docs/METADATA.md](./docs/METADATA.md)**
816
286
 
817
287
  ---
818
288
 
819
- ## โšก Lifecycle Events _(new in v3)_
820
-
821
- Subscribe to internal module lifecycle events:
289
+ ## โšก Lifecycle Events
822
290
 
823
- ```js
824
- // Available events
825
- api.slothlet.lifecycle.on("materialized:complete", (data) => {
826
- console.log(`${data.total} modules materialized`);
291
+ ```javascript
292
+ api.slothlet.lifecycle.on("materialized:complete", ({ total }) => console.log(`${total} modules ready`));
293
+ api.slothlet.lifecycle.on("impl:created", ({ apiPath }) => {
294
+ /* โ€ฆ */
827
295
  });
828
-
829
- api.slothlet.lifecycle.on("impl:created", (data) => {
830
- console.log(`Module created at ${data.apiPath}`);
296
+ api.slothlet.lifecycle.on("impl:changed", ({ apiPath }) => {
297
+ /* reload notify */
831
298
  });
832
-
833
- api.slothlet.lifecycle.on("impl:changed", (data) => {
834
- console.log(`Module at ${data.apiPath} was reloaded`);
299
+ api.slothlet.lifecycle.on("impl:removed", ({ apiPath }) => {
300
+ /* cleanup */
835
301
  });
836
-
837
- api.slothlet.lifecycle.on("impl:removed", (data) => {
838
- console.log(`Module at ${data.apiPath} was removed`);
839
- });
840
-
841
- // Unsubscribe
842
- const handler = (data) => console.log(data);
843
- api.slothlet.lifecycle.on("impl:changed", handler);
844
- api.slothlet.lifecycle.off("impl:changed", handler);
845
302
  ```
846
303
 
847
- **Available events**: `"materialized:complete"`, `"impl:created"`, `"impl:changed"`, `"impl:removed"`
304
+ Events: `materialized:complete`, `impl:created`, `impl:changed`, `impl:removed`. Public surface is `on` / `off` only.
848
305
 
849
- > [!NOTE]
850
- > `api.slothlet.lifecycle` exposes **`on` and `off` only**. `emit`, `subscribe`, and `unsubscribe` are internal - they are not present on the public API object.
306
+ โšก **Full reference: [docs/LIFECYCLE.md](./docs/LIFECYCLE.md)**
851
307
 
852
308
  ---
853
309
 
854
- ## ๐Ÿ“ File Organization Best Practices
855
-
856
- ### โœ… Clean Folder Structure
310
+ ## ๐Ÿ“ Module Structure
857
311
 
858
312
  ```text
859
313
  api/
860
314
  โ”œโ”€โ”€ config.mjs โ†’ api.config.*
861
315
  โ”œโ”€โ”€ math/
862
- โ”‚ โ””โ”€โ”€ math.mjs โ†’ api.math.* (flattened - filename matches folder)
316
+ โ”‚ โ””โ”€โ”€ math.mjs โ†’ api.math.* (flattened โ€” filename matches folder)
863
317
  โ”œโ”€โ”€ util/
864
- โ”‚ โ”œโ”€โ”€ util.mjs โ†’ api.util.* (flattened methods)
318
+ โ”‚ โ”œโ”€โ”€ util.mjs โ†’ api.util.* (flattened methods)
865
319
  โ”‚ โ”œโ”€โ”€ extract.mjs โ†’ api.util.extract.*
866
320
  โ”‚ โ””โ”€โ”€ controller.mjs โ†’ api.util.controller.*
867
- โ”œโ”€โ”€ nested/
868
- โ”‚ โ””โ”€โ”€ date/
869
- โ”‚ โ””โ”€โ”€ date.mjs โ†’ api.nested.date.*
870
- โ””โ”€โ”€ multi/
871
- โ”œโ”€โ”€ alpha.mjs โ†’ api.multi.alpha.*
872
- โ””โ”€โ”€ beta.mjs โ†’ api.multi.beta.*
321
+ โ””โ”€โ”€ nested/date/date.mjs โ†’ api.nested.date.*
873
322
  ```
874
323
 
875
- ### โœ… Naming Conventions
324
+ API modules **must never import each other directly** โ€” use the live-binding runtime:
876
325
 
877
- - **Filename matches folder** โ†’ Auto-flattening (`math/math.mjs` โ†’ `api.math.*`)
878
- - **Different filename** โ†’ Nested structure preserved
879
- - **Dash-separated names** โ†’ camelCase API (`auto-ip.mjs` โ†’ `api.autoIP`)
880
- - **Function name preferred** โ†’ Original capitalization kept over sanitized form (see [Rule 9](docs/API-RULES.md))
881
-
882
- ### โœ… Use `self` for Cross-Module Access
883
-
884
- API modules must never import each other directly. Use Slothlet's live-binding system instead:
885
-
886
- ```js
887
- // โŒ WRONG - breaks lazy loading and context isolation
326
+ ```javascript
327
+ // โŒ WRONG โ€” breaks lazy loading and context isolation
888
328
  import { math } from "./math/math.mjs";
889
329
 
890
- // โœ… CORRECT - live binding always reflects current runtime state
330
+ // โœ… CORRECT โ€” always reflects current runtime state
891
331
  import { self, context, instanceID } from "@cldmv/slothlet/runtime";
892
332
 
893
333
  export const myModule = {
894
334
  async processData(input) {
895
- const mathResult = self.math.add(2, 3); // Cross-module call via runtime
896
- console.log(`[${instanceID}] caller=${context.userId}`); // Per-request context + instance ID
897
- return `Processed: ${input}, Math: ${mathResult}`;
335
+ const r = self.math.add(2, 3);
336
+ console.log(`[${instanceID}] caller=${context.userId}`);
337
+ return `Processed: ${input}, Math: ${r}`;
898
338
  }
899
339
  };
900
340
  ```
901
341
 
902
- > The same import works from `.mjs`, `.cjs` (via `require`), `.ts`, and `.mts`. The TypeScript path was fixed in v3.5.0 โ€” earlier versions could not import bare specifiers from `.ts` modules.
903
-
904
- ---
905
-
906
- ## ๐Ÿ“Š Performance Analysis
907
-
908
- For comprehensive performance benchmarks, analysis, and recommendations:
909
-
910
- **๐Ÿ“ˆ [See docs/PERFORMANCE.md](https://github.com/CLDMV/slothlet/blob/master/docs/PERFORMANCE.md)**
911
-
912
- Key highlights:
913
-
914
- - Detailed startup vs runtime performance comparison
915
- - Memory usage analysis by loading mode
916
- - Materialization cost breakdown by module type
917
- - Real-world performance recommendations
918
-
919
- [![CodeFactor]][codefactor_url] [![npms.io score]][npms_url]
920
-
921
- [![npm unpacked size]][npm_size_url] [![Repo size]][repo_size_url]
922
-
923
- ---
924
-
925
- ## ๐Ÿ“š Documentation
926
-
927
- ### Core Documentation
928
-
929
- - **[Performance Analysis](https://github.com/CLDMV/slothlet/blob/master/docs/PERFORMANCE.md)** - Detailed benchmarks and recommendations
930
- - **[Agent Usage Guide](AGENT-USAGE.md)** - Guide for AI agents building Slothlet API folders
931
- - **[Contributing Guide](CONTRIBUTING.md)** - How to contribute to the project
932
- - **[Security Policy](SECURITY.md)** - Security guidelines and reporting
933
- - **[Test Documentation](api_tests)** - Comprehensive test module examples
934
-
935
- ### Technical Guides
936
-
937
- - **[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
938
- - **[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
939
- - **[Context Propagation](https://github.com/CLDMV/slothlet/blob/master/docs/CONTEXT-PROPAGATION.md)** - EventEmitter and class instance context preservation
940
- - **[Metadata System](https://github.com/CLDMV/slothlet/blob/master/docs/METADATA.md)** - Function metadata tagging and runtime introspection for security, authorization, and auditing
941
- - **[Module Structure](https://github.com/CLDMV/slothlet/blob/master/docs/MODULE-STRUCTURE.md)** - Comprehensive module organization patterns and examples
942
- - **[Sanitization](https://github.com/CLDMV/slothlet/blob/master/docs/SANITIZATION.md)** - Property name sanitization rules
943
- - **[Internationalization](https://github.com/CLDMV/slothlet/blob/master/docs/I18N.md)** - i18n support, language configuration, and available translations
944
-
945
- ### API Rules & Transformation
946
-
947
- - **[API Rules](docs/API-RULES.md)** - All 13 API transformation rules with verified test examples
948
- - **[API Rules Conditions](docs/API-RULES/API-RULES-CONDITIONS.md)** - Complete technical reference of all conditional statements that control API generation
949
- - **[API Flattening](docs/API-RULES/API-FLATTENING.md)** - Flattening rules with decision tree and benefits
950
-
951
- ---
952
-
953
- ## ๐ŸŒŸ Migration from v2.x
342
+ The same import works from `.mjs`, `.cjs` (via `require`), `.ts`, and `.mts` (TypeScript path fixed in v3.5.0).
954
343
 
955
- 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.
344
+ ๐Ÿ—๏ธ **[Module structure patterns](./docs/MODULE-STRUCTURE.md)** ยท ๐Ÿ“ **[All 13 API transformation rules](./docs/API-RULES.md)**
956
345
 
957
346
  ---
958
347
 
@@ -965,42 +354,70 @@ try {
965
354
  await api.slothlet.api.add("plugins", "./dir");
966
355
  } catch (error) {
967
356
  console.error(error.message); // Translated error message
968
- console.error(error.hint); // Contextual hint for resolution
969
- console.error(error.code); // Machine-readable error code
357
+ console.error(error.hint); // Contextual hint for resolution
358
+ console.error(error.code); // Machine-readable error code
970
359
  }
971
360
  ```
972
361
 
973
362
  ---
974
363
 
975
- ## ๐Ÿ—๏ธ Production & Development Modes
976
-
977
- ### Production Ready โœ…
364
+ ## ๐Ÿ—๏ธ Production & Development
978
365
 
979
- - **Eager Mode**: Stable, battle-tested, maximum performance
366
+ - **Eager Mode**: Stable, battle-tested, maximum runtime performance
980
367
  - **Lazy Mode**: Production-ready with copy-left optimization
981
368
  - **Background Materialization**: Lazy startup + eager runtime performance
982
369
  - **Mixed Module Loading**: ESM/CJS interoperability fully supported
983
-
984
- ### Development Features ๐Ÿ› ๏ธ
985
-
986
- - **Debug Mode**: Comprehensive i18n-translated logging via `--slothletdebug` flag or `SLOTHLET_DEBUG=true`
987
- - **Development Check**: `devcheck.mjs` for environment validation
370
+ - **Debug Mode**: i18n-translated logging via `--slothletdebug` flag or `SLOTHLET_DEBUG=true`
988
371
  - **Source Detection**: Automatic `src/` vs `dist/` mode detection
989
- - **API Inspection**: `console.log(api.math)` and versioned dispatcher paths like `console.log(api.auth)` show real module contents (v3+)
372
+ - **API Inspection**: `console.log(api.math)` and versioned dispatcher paths show real module contents (v3+)
990
373
 
991
374
  ---
992
375
 
993
- ## ๐Ÿค Contributing
376
+ ## ๐Ÿ“š Documentation
377
+
378
+ ### Reference
994
379
 
995
- We welcome contributions! Please:
380
+ - **[Configuration Reference](./docs/CONFIGURATION.md)** โ€” every option with defaults, validation rules, and the `api.slothlet.diag.*` namespace
381
+ - **[Generated API Reference](./docs/generated/API.md)** โ€” auto-generated from JSDoc; the complete public surface
382
+ - **[Changelog](./docs/changelog/)** โ€” all release notes (v2 + v3)
383
+ - **[Migration Guide](./docs/MIGRATION.md)** โ€” upgrading from v2.x
996
384
 
997
- 1. **Review the code** in `src/lib/` for implementation details
998
- 2. **Report issues** with detailed reproduction steps
999
- 3. **Submit pull requests** with comprehensive tests
1000
- 4. **Provide feedback** on API design and performance
1001
- 5. **Documentation improvements** are always appreciated
385
+ ### Technical Guides
386
+
387
+ - **[Performance Analysis](./docs/PERFORMANCE.md)** โ€” startup vs runtime benchmarks, memory analysis, materialization cost breakdown
388
+ - **[Hook System](./docs/HOOKS.md)** โ€” 4 types, three-phase subsets, pattern matching, management API
389
+ - **[Permission System](./docs/PERMISSIONS.md)** โ€” rules, glob patterns, self-call bypass, read gating, runtime management
390
+ - **[Permission Conditions](./docs/PERMISSIONS-CONDITIONS.md)** โ€” `condition` field syntax: deep object matching, functions, OR arrays
391
+ - **[Context Propagation](./docs/CONTEXT-PROPAGATION.md)** โ€” per-request isolation, EventEmitter / class propagation, merge strategies
392
+ - **[Lifecycle Events](./docs/LIFECYCLE.md)** โ€” `materialized:complete`, `impl:*` events, subscription API
393
+ - **[Hot Reload & Dynamic API](./docs/RELOAD.md)** โ€” `add`, `remove`, `reload`, collision modes, mutation controls, eager vs lazy semantics
394
+ - **[Versioning](./docs/VERSIONING.md)** โ€” multi-version module dispatch, `versionDispatcher`, version metadata
395
+ - **[Metadata System](./docs/METADATA.md)** โ€” function metadata tagging for security, authorization, auditing
396
+ - **[Module Structure](./docs/MODULE-STRUCTURE.md)** โ€” organization patterns, examples, and the loading-pipeline diagram
397
+ - **[Sanitization](./docs/SANITIZATION.md)** โ€” filename โ†’ property-name transformation rules
398
+ - **[TypeScript Support](./docs/TYPESCRIPT.md)** โ€” fast mode (esbuild), strict mode (tsc), `.d.ts` generation
399
+ - **[Internationalization](./docs/I18N.md)** โ€” supported languages and configuration
400
+
401
+ ### API Rules & Transformation
402
+
403
+ - **[API Rules](./docs/API-RULES.md)** โ€” all 13 transformation rules with verified test examples
404
+ - **[API Rules Conditions](./docs/API-RULES/API-RULES-CONDITIONS.md)** โ€” every conditional that controls API generation
405
+ - **[API Flattening](./docs/API-RULES/API-FLATTENING.md)** โ€” flattening rules with decision tree
406
+
407
+ ### Repo
408
+
409
+ - **[Agent Usage Guide](./AGENT-USAGE.md)** โ€” for AI agents building Slothlet API folders
410
+ - **[Contributing](./CONTRIBUTING.md)** โ€” contribution guidelines
411
+ - **[Security Policy](./SECURITY.md)** โ€” security guidelines and reporting
412
+ - **[Test Documentation](./api_tests/)** โ€” comprehensive test module examples
413
+
414
+ [![CodeFactor]][codefactor_url] [![npms.io score]][npms_url] [![npm unpacked size]][npm_size_url] [![Repo size]][repo_size_url]
415
+
416
+ ---
417
+
418
+ ## ๐Ÿค Contributing
1002
419
 
1003
- See [CONTRIBUTING.md](CONTRIBUTING.md) for detailed contribution guidelines.
420
+ We welcome contributions! See **[CONTRIBUTING.md](./CONTRIBUTING.md)** for guidelines.
1004
421
 
1005
422
  [![Contributors]][contributors_url] [![Sponsor shinrai]][sponsor_url]
1006
423