@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.
- package/README.md +150 -732
- package/REFERENCE.md +2 -0
- package/dist/lib/builders/api_builder.mjs +1 -1
- package/dist/lib/handlers/module-manager.mjs +17 -0
- package/dist/lib/handlers/permission-manager.mjs +1 -1
- package/dist/lib/handlers/unified-wrapper.mjs +1 -1
- package/dist/lib/helpers/config.mjs +1 -1
- package/dist/lib/helpers/eventemitter-context.mjs +1 -1
- package/dist/lib/helpers/module-discovery.mjs +17 -0
- package/dist/lib/helpers/module-manifest-validator.mjs +17 -0
- package/dist/lib/helpers/module-sort.mjs +17 -0
- package/dist/lib/i18n/languages/de-de.json +23 -1
- package/dist/lib/i18n/languages/en-gb.json +23 -1
- package/dist/lib/i18n/languages/en-us.json +23 -1
- package/dist/lib/i18n/languages/es-es.json +23 -1
- package/dist/lib/i18n/languages/es-mx.json +23 -1
- package/dist/lib/i18n/languages/fr-fr.json +23 -1
- package/dist/lib/i18n/languages/hi-in.json +23 -1
- package/dist/lib/i18n/languages/ja-jp.json +23 -1
- package/dist/lib/i18n/languages/ko-kr.json +23 -1
- package/dist/lib/i18n/languages/pt-br.json +23 -1
- package/dist/lib/i18n/languages/ru-ru.json +23 -1
- package/dist/lib/i18n/languages/zh-cn.json +23 -1
- package/package.json +5 -9
- package/schemas/slothlet.module.schema.json +98 -0
- package/types/dist/lib/builders/api_builder.d.mts.map +1 -1
- package/types/dist/lib/handlers/module-manager.d.mts +29 -0
- package/types/dist/lib/handlers/module-manager.d.mts.map +1 -0
- package/types/dist/lib/handlers/permission-manager.d.mts +2 -0
- package/types/dist/lib/handlers/permission-manager.d.mts.map +1 -1
- package/types/dist/lib/handlers/unified-wrapper.d.mts.map +1 -1
- package/types/dist/lib/helpers/config.d.mts +2 -0
- package/types/dist/lib/helpers/config.d.mts.map +1 -1
- package/types/dist/lib/helpers/eventemitter-context.d.mts.map +1 -1
- package/types/dist/lib/helpers/module-discovery.d.mts +8 -0
- package/types/dist/lib/helpers/module-discovery.d.mts.map +1 -0
- package/types/dist/lib/helpers/module-manifest-validator.d.mts +14 -0
- package/types/dist/lib/helpers/module-manifest-validator.d.mts.map +1 -0
- package/types/dist/lib/helpers/module-sort.d.mts +2 -0
- 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
|
-
|
|
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
|
-
|
|
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.
|
|
46
|
+
### Latest: v3.8.0 (May 2026)
|
|
59
47
|
|
|
60
|
-
-
|
|
61
|
-
-
|
|
62
|
-
- **
|
|
63
|
-
- [View full v3.
|
|
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
|
-
**
|
|
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](
|
|
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
|
-
- **
|
|
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** _(
|
|
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](
|
|
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](
|
|
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
|
-
๐๏ธ **
|
|
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
|
-
//
|
|
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
|
-
|
|
205
|
-
const
|
|
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
|
-
|
|
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
|
-
|
|
188
|
+
**Lazy mode** with copy-left materialization โ all calls awaited, ~2.2ร faster startup:
|
|
228
189
|
|
|
229
190
|
```javascript
|
|
230
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
217
|
+
## ๐ Loading Modes
|
|
505
218
|
|
|
506
|
-
|
|
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
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
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
|
-
|
|
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
|
-
## ๐ฃ
|
|
236
|
+
## ๐ฃ Hooks
|
|
540
237
|
|
|
541
|
-
|
|
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
|
-
```
|
|
544
|
-
// Simple enable (default pattern "**")
|
|
240
|
+
```javascript
|
|
545
241
|
const api = await slothlet({ dir: "./api", hook: true });
|
|
546
242
|
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
//
|
|
701
|
-
const
|
|
702
|
-
await
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
##
|
|
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
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
820
|
-
|
|
821
|
-
Subscribe to internal module lifecycle events:
|
|
290
|
+
## โก Lifecycle Events
|
|
822
291
|
|
|
823
|
-
```
|
|
824
|
-
|
|
825
|
-
api.slothlet.lifecycle.on("
|
|
826
|
-
|
|
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
|
-
|
|
830
|
-
console.log(`Module created at ${data.apiPath}`);
|
|
297
|
+
api.slothlet.lifecycle.on("impl:changed", ({ apiPath }) => {
|
|
298
|
+
/* reload notify */
|
|
831
299
|
});
|
|
832
|
-
|
|
833
|
-
|
|
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
|
-
|
|
305
|
+
Events: `materialized:complete`, `impl:created`, `impl:changed`, `impl:removed`. Public surface is `on` / `off` only.
|
|
848
306
|
|
|
849
|
-
|
|
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
|
-
## ๐
|
|
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.*
|
|
317
|
+
โ โโโ math.mjs โ api.math.* (flattened โ filename matches folder)
|
|
863
318
|
โโโ util/
|
|
864
|
-
โ โโโ util.mjs โ api.util.*
|
|
319
|
+
โ โโโ util.mjs โ api.util.* (flattened methods)
|
|
865
320
|
โ โโโ extract.mjs โ api.util.extract.*
|
|
866
321
|
โ โโโ controller.mjs โ api.util.controller.*
|
|
867
|
-
|
|
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
|
-
|
|
325
|
+
API modules **must never import each other directly** โ use the live-binding runtime:
|
|
876
326
|
|
|
877
|
-
|
|
878
|
-
|
|
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
|
|
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
|
|
896
|
-
console.log(`[${instanceID}] caller=${context.userId}`);
|
|
897
|
-
return `Processed: ${input}, Math: ${
|
|
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
|
-
|
|
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
|
-
|
|
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);
|
|
969
|
-
console.error(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
|
|
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
|
|
373
|
+
- **API Inspection**: `console.log(api.math)` and versioned dispatcher paths show real module contents (v3+)
|
|
990
374
|
|
|
991
375
|
---
|
|
992
376
|
|
|
993
|
-
##
|
|
377
|
+
## ๐ Documentation
|
|
378
|
+
|
|
379
|
+
### Reference
|
|
994
380
|
|
|
995
|
-
|
|
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
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
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
|
|
421
|
+
We welcome contributions! See **[CONTRIBUTING.md](./CONTRIBUTING.md)** for guidelines.
|
|
1004
422
|
|
|
1005
423
|
[![Contributors]][contributors_url] [![Sponsor shinrai]][sponsor_url]
|
|
1006
424
|
|