@cldmv/slothlet 3.6.0 โ†’ 3.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/README.md +150 -732
  2. package/REFERENCE.md +2 -0
  3. package/dist/lib/builders/api_builder.mjs +1 -1
  4. package/dist/lib/handlers/module-manager.mjs +17 -0
  5. package/dist/lib/handlers/permission-manager.mjs +1 -1
  6. package/dist/lib/handlers/unified-wrapper.mjs +1 -1
  7. package/dist/lib/helpers/config.mjs +1 -1
  8. package/dist/lib/helpers/eventemitter-context.mjs +1 -1
  9. package/dist/lib/helpers/module-discovery.mjs +17 -0
  10. package/dist/lib/helpers/module-manifest-validator.mjs +17 -0
  11. package/dist/lib/helpers/module-sort.mjs +17 -0
  12. package/dist/lib/i18n/languages/de-de.json +23 -1
  13. package/dist/lib/i18n/languages/en-gb.json +23 -1
  14. package/dist/lib/i18n/languages/en-us.json +23 -1
  15. package/dist/lib/i18n/languages/es-es.json +23 -1
  16. package/dist/lib/i18n/languages/es-mx.json +23 -1
  17. package/dist/lib/i18n/languages/fr-fr.json +23 -1
  18. package/dist/lib/i18n/languages/hi-in.json +23 -1
  19. package/dist/lib/i18n/languages/ja-jp.json +23 -1
  20. package/dist/lib/i18n/languages/ko-kr.json +23 -1
  21. package/dist/lib/i18n/languages/pt-br.json +23 -1
  22. package/dist/lib/i18n/languages/ru-ru.json +23 -1
  23. package/dist/lib/i18n/languages/zh-cn.json +23 -1
  24. package/package.json +5 -9
  25. package/schemas/slothlet.module.schema.json +98 -0
  26. package/types/dist/lib/builders/api_builder.d.mts.map +1 -1
  27. package/types/dist/lib/handlers/module-manager.d.mts +29 -0
  28. package/types/dist/lib/handlers/module-manager.d.mts.map +1 -0
  29. package/types/dist/lib/handlers/permission-manager.d.mts +2 -0
  30. package/types/dist/lib/handlers/permission-manager.d.mts.map +1 -1
  31. package/types/dist/lib/handlers/unified-wrapper.d.mts.map +1 -1
  32. package/types/dist/lib/helpers/config.d.mts +2 -0
  33. package/types/dist/lib/helpers/config.d.mts.map +1 -1
  34. package/types/dist/lib/helpers/eventemitter-context.d.mts.map +1 -1
  35. package/types/dist/lib/helpers/module-discovery.d.mts +8 -0
  36. package/types/dist/lib/helpers/module-discovery.d.mts.map +1 -0
  37. package/types/dist/lib/helpers/module-manifest-validator.d.mts +14 -0
  38. package/types/dist/lib/helpers/module-manifest-validator.d.mts.map +1 -0
  39. package/types/dist/lib/helpers/module-sort.d.mts +2 -0
  40. package/types/dist/lib/helpers/module-sort.d.mts.map +1 -0
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,25 @@ 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.8.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
+ - **Module discovery + mount pipeline** โ€” new `api.slothlet.api.modules.*` namespace composes subsystems shipped as separate npm packages into a host's api tree at runtime. Each module package ships a `slothlet.module.json` manifest declaring where it mounts; slothlet walks the filesystem, validates the manifests, and grafts each module onto the api tree. `discover` / `sort` / `addModule` / `addModules` / `addDiscovered` / `removeModule` plus a canonical JSON Schema at `schemas/slothlet.module.schema.json`.
49
+ - **Multi-version routing** โ€” when a single `addModules` call receives two or more entries sharing a `packageName` at different `version`s, each routes through slothlet's existing `versionConfig` system: every version lands at `vMAJOR.<mountPath>` and the highest semver becomes the registered default. Both versioned and dispatched access work transparently.
50
+ - **Five new lifecycle events + new `metadata.getFor(path)` wrapper** โ€” `modules:discover-start` / `-complete`, `modules:mount-start` / `-complete`, `modules:loaded` observe the full pipeline. `metadata.getFor(pathOrModuleId)` rounds out the path-based metadata API (symmetric with the existing `setFor` / `removeFor`).
51
+ - [View full v3.8.0 Changelog](./docs/changelog/v3/v3.8.0.md)
64
52
 
65
53
  ### Recent Releases
66
54
 
55
+ - **v3.7.0** (May 2026) โ€” Read-level permission gating: data-value reads are now permission-checked alongside function calls; `defaultPolicy: "deny"` now blocks cross-module data reads unless an allow rule covers the path ([Changelog](./docs/changelog/v3/v3.7.0.md))
56
+ - **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
57
  - **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
58
  - **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
- - **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
59
 
73
60
  ๐Ÿ“š **For complete version history and detailed release notes, see [docs/changelog/](./docs/changelog/) folder.**
74
61
 
@@ -95,12 +82,7 @@ Every feature has been hardened with a comprehensive test suite - over **5,300 t
95
82
  - **Zero dependencies**: Pure Node.js implementation
96
83
  - **Memory efficiency**: Lazy mode loads modules on-demand, eager mode optimizes for predictable behavior
97
84
 
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)**
85
+ ๐Ÿ“Š **For comprehensive performance benchmarks and analysis, see [docs/PERFORMANCE.md](./docs/PERFORMANCE.md)**
104
86
 
105
87
  ### ๐ŸŽฃ **Hook System** _(redesigned in v3)_
106
88
 
@@ -113,28 +95,27 @@ Powerful function interceptor system with 4 hook types and three-phase subset or
113
95
 
114
96
  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
97
 
116
- ๐ŸŽฃ **For complete hook system documentation, see [docs/HOOKS.md](https://github.com/CLDMV/slothlet/blob/master/docs/HOOKS.md)**
98
+ ๐ŸŽฃ **For complete hook system documentation, see [docs/HOOKS.md](./docs/HOOKS.md)**
117
99
 
118
- ### ๐Ÿ” **Permission System** _(new in v3.3)_
100
+ ### ๐Ÿ” **Permission System** _(new in v3.3, read-gated in v3.7)_
119
101
 
120
- Path-based access control for inter-module API calls:
102
+ Path-based access control for inter-module API calls **and** data-value reads (v3.7+):
121
103
 
122
104
  - **Glob pattern rules** โ€” same `*`, `**`, `?`, `{a,b}` syntax as hooks
123
105
  - **Most-specific-wins** โ€” exact patterns override broad globs; tiebreak by registration order
124
106
  - **Self-call bypass** โ€” calls within the same source file always succeed
125
- - **Enforcement before hooks** โ€” denied calls never trigger `before:` hooks or function execution
107
+ - **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
108
  - **Audit events** โ€” `permission:denied`, `permission:allowed`, `permission:default`, `permission:self-bypass`
127
109
  - **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
110
+ - **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
111
 
130
- ๐Ÿ” **For complete permission system documentation, see [docs/PERMISSIONS.md](https://github.com/CLDMV/slothlet/blob/master/docs/PERMISSIONS.md)**
112
+ ๐Ÿ” **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
113
 
132
114
  ### ๐ŸŒ **Full Internationalization** _(new in v3)_
133
115
 
134
- All error messages and debug output are translated. Supported languages:
135
- English ยท Spanish ยท French ยท German ยท Portuguese ยท Italian ยท Japanese ยท Chinese (Simplified) ยท Korean
116
+ All error messages and debug output are translated. Supported languages: English ยท Spanish ยท French ยท German ยท Portuguese ยท Italian ยท Japanese ยท Chinese (Simplified) ยท Korean
136
117
 
137
- Configure via `i18n: { language: "es" }` in your slothlet config.
118
+ Configure via `i18n: { language: "es" }` in your slothlet config. See **[docs/I18N.md](./docs/I18N.md)**.
138
119
 
139
120
  ### ๐Ÿ”„ **Context Propagation**
140
121
 
@@ -145,7 +126,7 @@ Automatic context preservation across all asynchronous boundaries:
145
126
  - **Class instance propagation**: Context preserved in class method calls
146
127
  - **Zero configuration**: Works automatically with TCP servers, HTTP servers, and custom EventEmitters
147
128
 
148
- ๐Ÿ”„ **For context propagation details, see [docs/CONTEXT-PROPAGATION.md](https://github.com/CLDMV/slothlet/blob/master/docs/CONTEXT-PROPAGATION.md)**
129
+ ๐Ÿ”„ **For context propagation details, see [docs/CONTEXT-PROPAGATION.md](./docs/CONTEXT-PROPAGATION.md)**
149
130
 
150
131
  ### ๐Ÿ”ง **Smart API Management**
151
132
 
@@ -154,8 +135,7 @@ Automatic context preservation across all asynchronous boundaries:
154
135
  - **Advanced Sanitization**: Custom naming rules with glob and boundary patterns; `api.slothlet.sanitize()` at runtime
155
136
  - **Hybrid Exports**: Support for callable APIs with methods, default + named exports
156
137
 
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)**
138
+ ๐Ÿ—๏ธ **[Module structure](./docs/MODULE-STRUCTURE.md)** ยท ๐Ÿ“ **[API flattening](./docs/API-RULES/API-FLATTENING.md)** ยท ๐Ÿ”ก **[Sanitization](./docs/SANITIZATION.md)**
159
139
 
160
140
  ### ๐Ÿ”— **Runtime & Context System**
161
141
 
@@ -166,7 +146,7 @@ Automatic context preservation across all asynchronous boundaries:
166
146
 
167
147
  ### ๐Ÿ›  **Developer Experience**
168
148
 
169
- - **TypeScript-Friendly**: Comprehensive JSDoc annotations with auto-generated declarations
149
+ - **TypeScript-Friendly**: Comprehensive JSDoc annotations with auto-generated declarations โ€” see **[docs/TYPESCRIPT.md](./docs/TYPESCRIPT.md)**
170
150
  - **Configurable Debug**: Detailed logging via CLI flags or environment variables
171
151
  - **Multiple Instances**: Parameter-based isolation for complex applications
172
152
  - **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 +170,179 @@ npm install @cldmv/slothlet
190
170
 
191
171
  ## ๐Ÿš€ Quick Start
192
172
 
193
- ### ESM (ES Modules)
194
-
195
173
  ```javascript
196
174
  import slothlet from "@cldmv/slothlet";
197
175
 
198
- // Direct usage - eager mode by default
176
+ // Eager mode (default) โ€” functions behave as originally defined
199
177
  const api = await slothlet({
200
178
  dir: "./api",
201
179
  context: { user: "alice" }
202
180
  });
203
181
 
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);
182
+ const result = api.math.add(2, 3); // Sync stays sync
183
+ const asyncResult = await api.async.process(); // Async stays async
211
184
  ```
212
185
 
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
- ```
186
+ CommonJS works the same way: `const slothlet = require("@cldmv/slothlet")`.
226
187
 
227
- ### Lazy Loading Mode
188
+ **Lazy mode** with copy-left materialization โ€” all calls awaited, ~2.2ร— faster startup:
228
189
 
229
190
  ```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);
191
+ const api = await slothlet({ mode: "lazy", dir: "./api" });
192
+ const result = await api.math.add(2, 3); // ALL calls awaited in lazy mode
297
193
  ```
298
194
 
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
- ```
195
+ **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
196
 
325
197
  ---
326
198
 
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` |
199
+ ## ๐Ÿ“š Configuration
346
200
 
347
- ---
201
+ 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
202
 
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
- ---
203
+ | Option | Type | Default | Description |
204
+ | ------------- | -------- | ----------- | ---------------------------------------------------------------------------------- |
205
+ | `dir` | `string` | `"api"` | Directory to load API modules from |
206
+ | `mode` | `string` | `"eager"` | `"eager"` (load upfront) or `"lazy"` (on-demand with copy-left materialization) |
207
+ | `runtime` | `string` | `"async"` | `"async"` (AsyncLocalStorage) or `"live"` (live-bindings) |
208
+ | `context` | `object` | `{}` | Per-request context โ€” read via `import { context } from "@cldmv/slothlet/runtime"` |
209
+ | `hook` | `mixed` | `false` | Enable hooks; see **[HOOKS.md](./docs/HOOKS.md)** |
210
+ | `permissions` | `object` | `undefined` | Path-based access control; see **[PERMISSIONS.md](./docs/PERMISSIONS.md)** |
211
+ | `i18n` | `object` | `{}` | Language for translated error/debug messages โ€” see **[I18N.md](./docs/I18N.md)** |
464
212
 
465
- ## ๐Ÿš€ Performance Modes
213
+ 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
214
 
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)
215
+ ---
503
216
 
504
- ### Lazy Mode with Background Materialization _(new in v3)_
217
+ ## ๐Ÿ”€ Loading Modes
505
218
 
506
- **Best for:** Lazy startup performance with eager runtime performance - pre-warm everything in the background
219
+ | Mode | Startup | Function calls | Best for |
220
+ | -------------------------------------- | -------------- | --------------------------------------------- | --------------------------------------------------- |
221
+ | **Eager** (default) | Loads upfront | Sync stays sync, async stays async | Production, predictable performance |
222
+ | **Lazy** | 2.2ร— faster | All calls awaited; materialized on first use | Large APIs, startup-sensitive apps |
223
+ | **Lazy + `backgroundMaterialize`** | 2.2ร— faster | Pre-warmed by background loader | Best of both โ€” lazy startup, eager runtime |
507
224
 
508
225
  ```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 }
226
+ // Lazy + background materialization
227
+ const api = await slothlet({ mode: "lazy", dir: "./api", backgroundMaterialize: true });
228
+ api.slothlet.lifecycle.on("materialized:complete", ({ total }) => console.log(`${total} modules ready`));
229
+ await api.slothlet.materialize.wait(); // optional: gate traffic on ready
526
230
  ```
527
231
 
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`
232
+ ๐Ÿ“Š **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
233
 
537
234
  ---
538
235
 
539
- ## ๐ŸŽฃ Hook System _(v3)_
236
+ ## ๐ŸŽฃ Hooks
540
237
 
541
- ### Hook Configuration
238
+ Four hook types (`before`, `after`, `always`, `error`) with three-phase subset ordering (`"before"` โ†’ `"primary"` โ†’ `"after"`), pattern matching, priority, and runtime enable/disable.
542
239
 
543
- ```js
544
- // Simple enable (default pattern "**")
240
+ ```javascript
545
241
  const api = await slothlet({ dir: "./api", hook: true });
546
242
 
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
- ```
243
+ api.slothlet.hook.on("before:math.add", ({ args }) => [args[0] * 2, args[1] * 2], { id: "double" });
244
+ api.slothlet.hook.on("after:math.*", ({ result }) => result * 10, { id: "scale" });
245
+ api.slothlet.hook.on("always:**", ({ path, hasError }) => console.log(path, hasError));
246
+ api.slothlet.hook.on("error:**", ({ path, error, source }) => console.error(path, source.type, error));
614
247
 
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
- );
248
+ const out = await api.math.add(2, 3); // hooks fire automatically
646
249
  ```
647
250
 
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
- ```
251
+ ๐ŸŽฃ **Configuration, all four types, subsets, pattern syntax, management API: [docs/HOOKS.md](./docs/HOOKS.md)**
682
252
 
683
253
  ---
684
254
 
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
- });
255
+ ## ๐Ÿ”„ Per-Request Context
692
256
 
693
- // run() - execute a function inside a scoped context
257
+ ```javascript
258
+ // Scoped context for a single call
694
259
  await api.slothlet.context.run({ userId: "alice", role: "admin" }, async () => {
695
- // Inside this scope: context = { appName, version, userId, role }
696
260
  await api.database.query();
697
261
  await api.audit.log();
698
262
  });
699
263
 
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
- );
264
+ // Derived API with merged context
265
+ const scoped = api.slothlet.context.scope({ userId: "bob" });
266
+ await scoped.database.query();
710
267
  ```
711
268
 
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
- ```
269
+ 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
270
 
735
- > ๐Ÿ“– See [`docs/CONTEXT-PROPAGATION.md`](docs/CONTEXT-PROPAGATION.md)
271
+ ๐Ÿ”„ **Full reference, isolation guarantees, merge strategies, TCP/HTTP examples: [docs/CONTEXT-PROPAGATION.md](./docs/CONTEXT-PROPAGATION.md)**
736
272
 
737
273
  ---
738
274
 
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.
275
+ ## ๐Ÿ” Hot Reload & Dynamic API
776
276
 
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
- });
277
+ ```javascript
278
+ await api.slothlet.api.add("plugins", "./plugins-folder"); // add at runtime
279
+ await api.slothlet.api.add("plugins.trusted", "./trusted", { metadata: { trusted: true } });
280
+ await api.slothlet.api.remove("oldModule"); // remove
281
+ await api.slothlet.api.reload("database.*"); // hot-reload
791
282
  ```
792
283
 
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)_
284
+ 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
285
 
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
- ```
286
+ ๐Ÿ” **Full reference: [docs/RELOAD.md](./docs/RELOAD.md)** ยท ๐Ÿท๏ธ **Metadata system: [docs/METADATA.md](./docs/METADATA.md)**
816
287
 
817
288
  ---
818
289
 
819
- ## โšก Lifecycle Events _(new in v3)_
820
-
821
- Subscribe to internal module lifecycle events:
290
+ ## โšก Lifecycle Events
822
291
 
823
- ```js
824
- // Available events
825
- api.slothlet.lifecycle.on("materialized:complete", (data) => {
826
- console.log(`${data.total} modules materialized`);
292
+ ```javascript
293
+ api.slothlet.lifecycle.on("materialized:complete", ({ total }) => console.log(`${total} modules ready`));
294
+ api.slothlet.lifecycle.on("impl:created", ({ apiPath }) => {
295
+ /* โ€ฆ */
827
296
  });
828
-
829
- api.slothlet.lifecycle.on("impl:created", (data) => {
830
- console.log(`Module created at ${data.apiPath}`);
297
+ api.slothlet.lifecycle.on("impl:changed", ({ apiPath }) => {
298
+ /* reload notify */
831
299
  });
832
-
833
- api.slothlet.lifecycle.on("impl:changed", (data) => {
834
- console.log(`Module at ${data.apiPath} was reloaded`);
300
+ api.slothlet.lifecycle.on("impl:removed", ({ apiPath }) => {
301
+ /* cleanup */
835
302
  });
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
303
  ```
846
304
 
847
- **Available events**: `"materialized:complete"`, `"impl:created"`, `"impl:changed"`, `"impl:removed"`
305
+ Events: `materialized:complete`, `impl:created`, `impl:changed`, `impl:removed`. Public surface is `on` / `off` only.
848
306
 
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.
307
+ โšก **Full reference: [docs/LIFECYCLE.md](./docs/LIFECYCLE.md)**
851
308
 
852
309
  ---
853
310
 
854
- ## ๐Ÿ“ File Organization Best Practices
855
-
856
- ### โœ… Clean Folder Structure
311
+ ## ๐Ÿ“ Module Structure
857
312
 
858
313
  ```text
859
314
  api/
860
315
  โ”œโ”€โ”€ config.mjs โ†’ api.config.*
861
316
  โ”œโ”€โ”€ math/
862
- โ”‚ โ””โ”€โ”€ math.mjs โ†’ api.math.* (flattened - filename matches folder)
317
+ โ”‚ โ””โ”€โ”€ math.mjs โ†’ api.math.* (flattened โ€” filename matches folder)
863
318
  โ”œโ”€โ”€ util/
864
- โ”‚ โ”œโ”€โ”€ util.mjs โ†’ api.util.* (flattened methods)
319
+ โ”‚ โ”œโ”€โ”€ util.mjs โ†’ api.util.* (flattened methods)
865
320
  โ”‚ โ”œโ”€โ”€ extract.mjs โ†’ api.util.extract.*
866
321
  โ”‚ โ””โ”€โ”€ 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.*
322
+ โ””โ”€โ”€ nested/date/date.mjs โ†’ api.nested.date.*
873
323
  ```
874
324
 
875
- ### โœ… Naming Conventions
325
+ API modules **must never import each other directly** โ€” use the live-binding runtime:
876
326
 
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
327
+ ```javascript
328
+ // โŒ WRONG โ€” breaks lazy loading and context isolation
888
329
  import { math } from "./math/math.mjs";
889
330
 
890
- // โœ… CORRECT - live binding always reflects current runtime state
331
+ // โœ… CORRECT โ€” always reflects current runtime state
891
332
  import { self, context, instanceID } from "@cldmv/slothlet/runtime";
892
333
 
893
334
  export const myModule = {
894
335
  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}`;
336
+ const r = self.math.add(2, 3);
337
+ console.log(`[${instanceID}] caller=${context.userId}`);
338
+ return `Processed: ${input}, Math: ${r}`;
898
339
  }
899
340
  };
900
341
  ```
901
342
 
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
343
+ The same import works from `.mjs`, `.cjs` (via `require`), `.ts`, and `.mts` (TypeScript path fixed in v3.5.0).
954
344
 
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.
345
+ ๐Ÿ—๏ธ **[Module structure patterns](./docs/MODULE-STRUCTURE.md)** ยท ๐Ÿ“ **[All 13 API transformation rules](./docs/API-RULES.md)**
956
346
 
957
347
  ---
958
348
 
@@ -965,42 +355,70 @@ try {
965
355
  await api.slothlet.api.add("plugins", "./dir");
966
356
  } catch (error) {
967
357
  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
358
+ console.error(error.hint); // Contextual hint for resolution
359
+ console.error(error.code); // Machine-readable error code
970
360
  }
971
361
  ```
972
362
 
973
363
  ---
974
364
 
975
- ## ๐Ÿ—๏ธ Production & Development Modes
976
-
977
- ### Production Ready โœ…
365
+ ## ๐Ÿ—๏ธ Production & Development
978
366
 
979
- - **Eager Mode**: Stable, battle-tested, maximum performance
367
+ - **Eager Mode**: Stable, battle-tested, maximum runtime performance
980
368
  - **Lazy Mode**: Production-ready with copy-left optimization
981
369
  - **Background Materialization**: Lazy startup + eager runtime performance
982
370
  - **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
371
+ - **Debug Mode**: i18n-translated logging via `--slothletdebug` flag or `SLOTHLET_DEBUG=true`
988
372
  - **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+)
373
+ - **API Inspection**: `console.log(api.math)` and versioned dispatcher paths show real module contents (v3+)
990
374
 
991
375
  ---
992
376
 
993
- ## ๐Ÿค Contributing
377
+ ## ๐Ÿ“š Documentation
378
+
379
+ ### Reference
994
380
 
995
- We welcome contributions! Please:
381
+ - **[Configuration Reference](./docs/CONFIGURATION.md)** โ€” every option with defaults, validation rules, and the `api.slothlet.diag.*` namespace
382
+ - **[Generated API Reference](./docs/generated/API.md)** โ€” auto-generated from JSDoc; the complete public surface
383
+ - **[Changelog](./docs/changelog/)** โ€” all release notes (v2 + v3)
384
+ - **[Migration Guide](./docs/MIGRATION.md)** โ€” upgrading from v2.x
996
385
 
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
386
+ ### Technical Guides
387
+
388
+ - **[Performance Analysis](./docs/PERFORMANCE.md)** โ€” startup vs runtime benchmarks, memory analysis, materialization cost breakdown
389
+ - **[Hook System](./docs/HOOKS.md)** โ€” 4 types, three-phase subsets, pattern matching, management API
390
+ - **[Permission System](./docs/PERMISSIONS.md)** โ€” rules, glob patterns, self-call bypass, read gating, runtime management
391
+ - **[Permission Conditions](./docs/PERMISSIONS-CONDITIONS.md)** โ€” `condition` field syntax: deep object matching, functions, OR arrays
392
+ - **[Context Propagation](./docs/CONTEXT-PROPAGATION.md)** โ€” per-request isolation, EventEmitter / class propagation, merge strategies
393
+ - **[Lifecycle Events](./docs/LIFECYCLE.md)** โ€” `materialized:complete`, `impl:*` events, subscription API
394
+ - **[Hot Reload & Dynamic API](./docs/RELOAD.md)** โ€” `add`, `remove`, `reload`, collision modes, mutation controls, eager vs lazy semantics
395
+ - **[Versioning](./docs/VERSIONING.md)** โ€” multi-version module dispatch, `versionDispatcher`, version metadata
396
+ - **[Metadata System](./docs/METADATA.md)** โ€” function metadata tagging for security, authorization, auditing
397
+ - **[Module Structure](./docs/MODULE-STRUCTURE.md)** โ€” organization patterns, examples, and the loading-pipeline diagram
398
+ - **[Sanitization](./docs/SANITIZATION.md)** โ€” filename โ†’ property-name transformation rules
399
+ - **[TypeScript Support](./docs/TYPESCRIPT.md)** โ€” fast mode (esbuild), strict mode (tsc), `.d.ts` generation
400
+ - **[Internationalization](./docs/I18N.md)** โ€” supported languages and configuration
401
+
402
+ ### API Rules & Transformation
403
+
404
+ - **[API Rules](./docs/API-RULES.md)** โ€” all 13 transformation rules with verified test examples
405
+ - **[API Rules Conditions](./docs/API-RULES/API-RULES-CONDITIONS.md)** โ€” every conditional that controls API generation
406
+ - **[API Flattening](./docs/API-RULES/API-FLATTENING.md)** โ€” flattening rules with decision tree
407
+
408
+ ### Repo
409
+
410
+ - **[Agent Usage Guide](./AGENT-USAGE.md)** โ€” for AI agents building Slothlet API folders
411
+ - **[Contributing](./CONTRIBUTING.md)** โ€” contribution guidelines
412
+ - **[Security Policy](./SECURITY.md)** โ€” security guidelines and reporting
413
+ - **[Test Documentation](./api_tests/)** โ€” comprehensive test module examples
414
+
415
+ [![CodeFactor]][codefactor_url] [![npms.io score]][npms_url] [![npm unpacked size]][npm_size_url] [![Repo size]][repo_size_url]
416
+
417
+ ---
418
+
419
+ ## ๐Ÿค Contributing
1002
420
 
1003
- See [CONTRIBUTING.md](CONTRIBUTING.md) for detailed contribution guidelines.
421
+ We welcome contributions! See **[CONTRIBUTING.md](./CONTRIBUTING.md)** for guidelines.
1004
422
 
1005
423
  [![Contributors]][contributors_url] [![Sponsor shinrai]][sponsor_url]
1006
424