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