@cldmv/slothlet 2.10.0 → 3.0.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/AGENT-USAGE.md +365 -294
- package/README.md +556 -233
- package/dist/lib/builders/api-assignment.mjs +605 -0
- package/dist/lib/builders/api_builder.mjs +1073 -0
- package/dist/lib/builders/builder.mjs +94 -0
- package/dist/lib/builders/modes-processor.mjs +1816 -0
- package/dist/lib/errors.mjs +227 -0
- package/dist/lib/factories/component-base.mjs +96 -0
- package/dist/lib/factories/context.mjs +38 -0
- package/dist/lib/handlers/api-cache-manager.mjs +216 -0
- package/dist/lib/handlers/api-manager.mjs +2364 -0
- package/dist/lib/handlers/context-async.mjs +184 -0
- package/dist/lib/handlers/context-live.mjs +184 -0
- package/dist/lib/handlers/hook-manager.mjs +789 -0
- package/dist/lib/handlers/lifecycle-token.mjs +44 -0
- package/dist/lib/handlers/lifecycle.mjs +131 -0
- package/dist/lib/handlers/materialize-manager.mjs +64 -0
- package/dist/lib/handlers/metadata.mjs +500 -0
- package/dist/lib/handlers/ownership.mjs +338 -0
- package/dist/lib/handlers/unified-wrapper.mjs +3031 -0
- package/dist/lib/helpers/class-instance-wrapper.mjs +125 -0
- package/dist/lib/helpers/config.mjs +343 -0
- package/dist/lib/helpers/eventemitter-context.mjs +365 -0
- package/dist/lib/helpers/hint-detector.mjs +63 -0
- package/dist/lib/helpers/modes-utils.mjs +53 -0
- package/dist/lib/helpers/resolve-from-caller.mjs +125 -85
- package/dist/lib/helpers/sanitize.mjs +247 -168
- package/dist/lib/helpers/utilities.mjs +46 -81
- package/dist/lib/i18n/languages/de-de.json +377 -0
- package/dist/lib/i18n/languages/en-gb.json +377 -0
- package/dist/lib/i18n/languages/en-us.json +377 -0
- package/dist/lib/i18n/languages/es-mx.json +377 -0
- package/dist/lib/i18n/languages/fr-fr.json +377 -0
- package/dist/lib/i18n/languages/hi-in.json +377 -0
- package/dist/lib/i18n/languages/ja-jp.json +377 -0
- package/dist/lib/i18n/languages/ko-kr.json +377 -0
- package/dist/lib/i18n/languages/pt-br.json +377 -0
- package/dist/lib/i18n/languages/ru-ru.json +377 -0
- package/dist/lib/i18n/languages/zh-cn.json +377 -0
- package/dist/lib/i18n/translations.mjs +140 -0
- package/dist/lib/modes/eager.mjs +75 -0
- package/dist/lib/modes/lazy.mjs +97 -0
- package/dist/lib/processors/flatten.mjs +453 -0
- package/dist/lib/processors/loader.mjs +355 -0
- package/dist/lib/processors/type-generator.mjs +291 -0
- package/dist/lib/processors/typescript.mjs +188 -0
- package/dist/lib/runtime/runtime-asynclocalstorage.mjs +80 -522
- package/dist/lib/runtime/runtime-livebindings.mjs +45 -390
- package/dist/lib/runtime/runtime.mjs +39 -159
- package/dist/slothlet.mjs +529 -700
- package/docs/API-RULES.md +497 -617
- package/index.cjs +4 -4
- package/index.mjs +82 -45
- package/package.json +139 -26
- package/types/dist/lib/builders/api-assignment.d.mts +97 -0
- package/types/dist/lib/builders/api-assignment.d.mts.map +1 -0
- package/types/dist/lib/builders/api_builder.d.mts +96 -0
- package/types/dist/lib/builders/api_builder.d.mts.map +1 -0
- package/types/dist/lib/builders/builder.d.mts +60 -0
- package/types/dist/lib/builders/builder.d.mts.map +1 -0
- package/types/dist/lib/builders/modes-processor.d.mts +32 -0
- package/types/dist/lib/builders/modes-processor.d.mts.map +1 -0
- package/types/dist/lib/errors.d.mts +118 -0
- package/types/dist/lib/errors.d.mts.map +1 -0
- package/types/dist/lib/factories/component-base.d.mts +182 -0
- package/types/dist/lib/factories/component-base.d.mts.map +1 -0
- package/types/dist/lib/factories/context.d.mts +26 -0
- package/types/dist/lib/factories/context.d.mts.map +1 -0
- package/types/dist/lib/handlers/api-cache-manager.d.mts +208 -0
- package/types/dist/lib/handlers/api-cache-manager.d.mts.map +1 -0
- package/types/dist/lib/handlers/api-manager.d.mts +392 -0
- package/types/dist/lib/handlers/api-manager.d.mts.map +1 -0
- package/types/dist/lib/handlers/context-async.d.mts +66 -0
- package/types/dist/lib/handlers/context-async.d.mts.map +1 -0
- package/types/dist/lib/handlers/context-live.d.mts +65 -0
- package/types/dist/lib/handlers/context-live.d.mts.map +1 -0
- package/types/dist/lib/handlers/hook-manager.d.mts +199 -0
- package/types/dist/lib/handlers/hook-manager.d.mts.map +1 -0
- package/types/dist/lib/handlers/lifecycle-token.d.mts +49 -0
- package/types/dist/lib/handlers/lifecycle-token.d.mts.map +1 -0
- package/types/dist/lib/handlers/lifecycle.d.mts +90 -0
- package/types/dist/lib/handlers/lifecycle.d.mts.map +1 -0
- package/types/dist/lib/handlers/materialize-manager.d.mts +75 -0
- package/types/dist/lib/handlers/materialize-manager.d.mts.map +1 -0
- package/types/dist/lib/handlers/metadata.d.mts +215 -0
- package/types/dist/lib/handlers/metadata.d.mts.map +1 -0
- package/types/dist/lib/handlers/ownership.d.mts +170 -0
- package/types/dist/lib/handlers/ownership.d.mts.map +1 -0
- package/types/dist/lib/handlers/unified-wrapper.d.mts +250 -0
- package/types/dist/lib/handlers/unified-wrapper.d.mts.map +1 -0
- package/types/dist/lib/helpers/class-instance-wrapper.d.mts +54 -0
- package/types/dist/lib/helpers/class-instance-wrapper.d.mts.map +1 -0
- package/types/dist/lib/helpers/config.d.mts +96 -0
- package/types/dist/lib/helpers/config.d.mts.map +1 -0
- package/types/dist/lib/helpers/eventemitter-context.d.mts +31 -0
- package/types/dist/lib/helpers/eventemitter-context.d.mts.map +1 -0
- package/types/dist/lib/helpers/hint-detector.d.mts +20 -0
- package/types/dist/lib/helpers/hint-detector.d.mts.map +1 -0
- package/types/dist/lib/helpers/modes-utils.d.mts +35 -0
- package/types/dist/lib/helpers/modes-utils.d.mts.map +1 -0
- package/types/dist/lib/helpers/resolve-from-caller.d.mts +29 -145
- package/types/dist/lib/helpers/resolve-from-caller.d.mts.map +1 -1
- package/types/dist/lib/helpers/sanitize.d.mts +95 -94
- package/types/dist/lib/helpers/sanitize.d.mts.map +1 -1
- package/types/dist/lib/helpers/utilities.d.mts +53 -116
- package/types/dist/lib/helpers/utilities.d.mts.map +1 -1
- package/types/dist/lib/i18n/translations.d.mts +39 -0
- package/types/dist/lib/i18n/translations.d.mts.map +1 -0
- package/types/dist/lib/modes/eager.d.mts +36 -0
- package/types/dist/lib/modes/eager.d.mts.map +1 -0
- package/types/dist/lib/modes/lazy.d.mts +49 -0
- package/types/dist/lib/modes/lazy.d.mts.map +1 -0
- package/types/dist/lib/processors/flatten.d.mts +114 -0
- package/types/dist/lib/processors/flatten.d.mts.map +1 -0
- package/types/dist/lib/processors/loader.d.mts +47 -0
- package/types/dist/lib/processors/loader.d.mts.map +1 -0
- package/types/dist/lib/processors/type-generator.d.mts +19 -0
- package/types/dist/lib/processors/type-generator.d.mts.map +1 -0
- package/types/dist/lib/processors/typescript.d.mts +55 -0
- package/types/dist/lib/processors/typescript.d.mts.map +1 -0
- package/types/dist/lib/runtime/runtime-asynclocalstorage.d.mts +47 -42
- package/types/dist/lib/runtime/runtime-asynclocalstorage.d.mts.map +1 -1
- package/types/dist/lib/runtime/runtime-livebindings.d.mts +34 -65
- package/types/dist/lib/runtime/runtime-livebindings.d.mts.map +1 -1
- package/types/dist/lib/runtime/runtime.d.mts +39 -9
- package/types/dist/lib/runtime/runtime.d.mts.map +1 -1
- package/types/dist/slothlet.d.mts +186 -105
- package/types/dist/slothlet.d.mts.map +1 -1
- package/types/index.d.mts +1 -3
- package/dist/lib/engine/README.md +0 -21
- package/dist/lib/engine/slothlet_child.mjs +0 -59
- package/dist/lib/engine/slothlet_engine.mjs +0 -372
- package/dist/lib/engine/slothlet_esm.mjs +0 -230
- package/dist/lib/engine/slothlet_helpers.mjs +0 -455
- package/dist/lib/engine/slothlet_worker.mjs +0 -149
- package/dist/lib/helpers/als-eventemitter.mjs +0 -256
- package/dist/lib/helpers/api_builder/add_api.mjs +0 -292
- package/dist/lib/helpers/api_builder/analysis.mjs +0 -532
- package/dist/lib/helpers/api_builder/construction.mjs +0 -457
- package/dist/lib/helpers/api_builder/decisions.mjs +0 -737
- package/dist/lib/helpers/api_builder/metadata.mjs +0 -248
- package/dist/lib/helpers/api_builder.mjs +0 -41
- package/dist/lib/helpers/auto-wrap.mjs +0 -62
- package/dist/lib/helpers/hooks.mjs +0 -389
- package/dist/lib/helpers/instance-manager.mjs +0 -111
- package/dist/lib/helpers/metadata-api.mjs +0 -201
- package/dist/lib/helpers/multidefault.mjs +0 -216
- package/dist/lib/modes/slothlet_eager.mjs +0 -126
- package/dist/lib/modes/slothlet_lazy.mjs +0 -513
- package/docs/API-RULES-CONDITIONS.md +0 -508
- package/types/dist/lib/engine/slothlet_child.d.mts +0 -2
- package/types/dist/lib/engine/slothlet_child.d.mts.map +0 -1
- package/types/dist/lib/engine/slothlet_engine.d.mts +0 -31
- package/types/dist/lib/engine/slothlet_engine.d.mts.map +0 -1
- package/types/dist/lib/engine/slothlet_esm.d.mts +0 -19
- package/types/dist/lib/engine/slothlet_esm.d.mts.map +0 -1
- package/types/dist/lib/engine/slothlet_helpers.d.mts +0 -25
- package/types/dist/lib/engine/slothlet_helpers.d.mts.map +0 -1
- package/types/dist/lib/engine/slothlet_worker.d.mts +0 -2
- package/types/dist/lib/engine/slothlet_worker.d.mts.map +0 -1
- package/types/dist/lib/helpers/als-eventemitter.d.mts +0 -56
- package/types/dist/lib/helpers/als-eventemitter.d.mts.map +0 -1
- package/types/dist/lib/helpers/api_builder/add_api.d.mts +0 -76
- package/types/dist/lib/helpers/api_builder/add_api.d.mts.map +0 -1
- package/types/dist/lib/helpers/api_builder/analysis.d.mts +0 -189
- package/types/dist/lib/helpers/api_builder/analysis.d.mts.map +0 -1
- package/types/dist/lib/helpers/api_builder/construction.d.mts +0 -107
- package/types/dist/lib/helpers/api_builder/construction.d.mts.map +0 -1
- package/types/dist/lib/helpers/api_builder/decisions.d.mts +0 -213
- package/types/dist/lib/helpers/api_builder/decisions.d.mts.map +0 -1
- package/types/dist/lib/helpers/api_builder/metadata.d.mts +0 -99
- package/types/dist/lib/helpers/api_builder/metadata.d.mts.map +0 -1
- package/types/dist/lib/helpers/api_builder.d.mts +0 -6
- package/types/dist/lib/helpers/api_builder.d.mts.map +0 -1
- package/types/dist/lib/helpers/auto-wrap.d.mts +0 -49
- package/types/dist/lib/helpers/auto-wrap.d.mts.map +0 -1
- package/types/dist/lib/helpers/hooks.d.mts +0 -342
- package/types/dist/lib/helpers/hooks.d.mts.map +0 -1
- package/types/dist/lib/helpers/instance-manager.d.mts +0 -41
- package/types/dist/lib/helpers/instance-manager.d.mts.map +0 -1
- package/types/dist/lib/helpers/metadata-api.d.mts +0 -132
- package/types/dist/lib/helpers/metadata-api.d.mts.map +0 -1
- package/types/dist/lib/helpers/multidefault.d.mts +0 -90
- package/types/dist/lib/helpers/multidefault.d.mts.map +0 -1
- package/types/dist/lib/modes/slothlet_eager.d.mts +0 -65
- package/types/dist/lib/modes/slothlet_eager.d.mts.map +0 -1
- package/types/dist/lib/modes/slothlet_lazy.d.mts +0 -31
- package/types/dist/lib/modes/slothlet_lazy.d.mts.map +0 -1
package/AGENT-USAGE.md
CHANGED
|
@@ -2,87 +2,68 @@
|
|
|
2
2
|
|
|
3
3
|
> **Critical**: This guide prevents AI agents from making architectural mistakes when building Slothlet API modules.
|
|
4
4
|
|
|
5
|
-
## 📋
|
|
5
|
+
## 📋 Related Documentation
|
|
6
6
|
|
|
7
|
-
- **[API-RULES.md](
|
|
8
|
-
- **[README.md](
|
|
9
|
-
- **[api_tests
|
|
7
|
+
- **[`docs/API-RULES.md`](docs/API-RULES.md)** - All 13 API transformation rules with verified test examples
|
|
8
|
+
- **[`README.md`](README.md)** - Complete project overview and usage examples
|
|
9
|
+
- **[`api_tests/*/README.md`](api_tests/)** - Live examples demonstrating each pattern below
|
|
10
10
|
|
|
11
11
|
---
|
|
12
12
|
|
|
13
13
|
## 🚫 NEVER DO: Cross-Module Imports
|
|
14
14
|
|
|
15
|
-
**The #1 mistake AI agents make with Slothlet**:
|
|
15
|
+
**The #1 mistake AI agents make with Slothlet**: Importing API files from each other.
|
|
16
16
|
|
|
17
17
|
```js
|
|
18
18
|
// ❌ WRONG - Do NOT import API modules from each other
|
|
19
19
|
import { math } from "./math/math.mjs"; // BREAKS SLOTHLET
|
|
20
20
|
import { config } from "../config.mjs"; // BREAKS SLOTHLET
|
|
21
21
|
import { util } from "./util/util.mjs"; // BREAKS SLOTHLET
|
|
22
|
-
|
|
23
|
-
// ❌ WRONG - Do NOT use relative imports between API modules
|
|
24
|
-
import { someFunction } from "../../other-api.mjs"; // BREAKS SLOTHLET
|
|
25
22
|
```
|
|
26
23
|
|
|
27
24
|
**Why this breaks Slothlet**:
|
|
28
25
|
|
|
29
|
-
- Slothlet builds
|
|
26
|
+
- Slothlet builds API structure dynamically at runtime
|
|
30
27
|
- Cross-imports create circular dependencies
|
|
31
28
|
- Breaks lazy loading and context isolation
|
|
32
|
-
- Defeats the purpose of module loading framework
|
|
29
|
+
- Defeats the purpose of the module loading framework
|
|
33
30
|
|
|
34
31
|
## ✅ CORRECT: Use Slothlet's Live-Binding System
|
|
35
32
|
|
|
36
33
|
```js
|
|
37
34
|
// ✅ CORRECT - Import from Slothlet runtime for cross-module access
|
|
38
|
-
import { self, context
|
|
35
|
+
import { self, context } from "@cldmv/slothlet/runtime";
|
|
39
36
|
|
|
40
|
-
// ✅ CORRECT - Access other modules through `self`
|
|
41
37
|
export const myModule = {
|
|
42
38
|
async processData(input) {
|
|
43
|
-
// Access other API modules via `self`
|
|
39
|
+
// Access other API modules via `self` (live binding - always current)
|
|
44
40
|
const mathResult = self.math.add(2, 3);
|
|
45
41
|
const configValue = self.config.get("setting");
|
|
46
|
-
|
|
47
|
-
|
|
42
|
+
// context holds the current request/call context
|
|
43
|
+
console.log(`Caller: ${context.userId}`);
|
|
44
|
+
return `Processed: ${input}, Math: ${mathResult}`;
|
|
48
45
|
}
|
|
49
46
|
};
|
|
50
47
|
```
|
|
51
48
|
|
|
52
|
-
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## 🏗️ API Module Patterns
|
|
53
52
|
|
|
54
53
|
### Pattern 1: Simple Object Export (Most Common)
|
|
55
54
|
|
|
56
55
|
**File**: `math/math.mjs` → **API**: `api.math.add()`, `api.math.multiply()`
|
|
57
56
|
|
|
58
57
|
```js
|
|
59
|
-
/**
|
|
60
|
-
* @fileoverview Math operations module. Internal file (not exported in package.json).
|
|
61
|
-
* @module api_test.math
|
|
62
|
-
* @memberof module:api_test
|
|
63
|
-
*/
|
|
64
|
-
|
|
65
|
-
// ✅ Import runtime for cross-module access (if needed)
|
|
66
|
-
// import { self, context, reference } from "@cldmv/slothlet/runtime";
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Math operations object accessed as `api.math`.
|
|
70
|
-
* @alias module:api_test.math
|
|
71
|
-
*/
|
|
72
58
|
export const math = {
|
|
73
|
-
add(a, b) {
|
|
74
|
-
|
|
75
|
-
},
|
|
76
|
-
|
|
77
|
-
multiply(a, b) {
|
|
78
|
-
return a * b;
|
|
79
|
-
}
|
|
59
|
+
add(a, b) { return a + b; },
|
|
60
|
+
multiply(a, b) { return a * b; }
|
|
80
61
|
};
|
|
81
62
|
```
|
|
82
63
|
|
|
83
64
|
**Result**: Filename matches folder (`math/math.mjs`) → Auto-flattening → `api.math.add()` (not `api.math.math.add()`)
|
|
84
65
|
|
|
85
|
-
> 📖
|
|
66
|
+
> 📖 See [API-RULES.md Rule 1](docs/API-RULES.md) for flattening details.
|
|
86
67
|
|
|
87
68
|
### Pattern 2: Multiple Files in Folder
|
|
88
69
|
|
|
@@ -90,47 +71,31 @@ export const math = {
|
|
|
90
71
|
|
|
91
72
|
```js
|
|
92
73
|
// File: multi/alpha.mjs
|
|
93
|
-
export const alpha = {
|
|
94
|
-
hello() {
|
|
95
|
-
return "alpha hello";
|
|
96
|
-
}
|
|
97
|
-
};
|
|
74
|
+
export const alpha = { hello() { return "alpha hello"; } };
|
|
98
75
|
|
|
99
76
|
// File: multi/beta.mjs
|
|
100
|
-
export const beta = {
|
|
101
|
-
world() {
|
|
102
|
-
return "beta world";
|
|
103
|
-
}
|
|
104
|
-
};
|
|
77
|
+
export const beta = { world() { return "beta world"; } };
|
|
105
78
|
```
|
|
106
79
|
|
|
107
|
-
**Result**: Different filenames from folder → No flattening → Nested structure preserved
|
|
108
|
-
|
|
109
|
-
> 📖 **See**: [API-RULES.md Rule 2](./API-RULES.md#rule-2-named-only-export-collection) for multi-file folder processing
|
|
80
|
+
**Result**: Different filenames from folder → No flattening → Nested structure preserved.
|
|
110
81
|
|
|
111
82
|
### Pattern 3: Default Function Export
|
|
112
83
|
|
|
113
84
|
**File**: `funcmod/funcmod.mjs` → **API**: `api.funcmod(name)`
|
|
114
85
|
|
|
115
86
|
```js
|
|
116
|
-
/**
|
|
117
|
-
* Default function export accessed as `api.funcmod()`.
|
|
118
|
-
* @param {string} name - Name to greet
|
|
119
|
-
* @returns {string} Greeting message
|
|
120
|
-
*/
|
|
121
87
|
export default function funcmod(name) {
|
|
122
88
|
return `Hello, ${name}!`;
|
|
123
89
|
}
|
|
124
90
|
```
|
|
125
91
|
|
|
126
|
-
**Result**: Filename matches folder + default export → Function flattened to `api.funcmod()
|
|
92
|
+
**Result**: Filename matches folder + default export → Function flattened to `api.funcmod()`.
|
|
127
93
|
|
|
128
94
|
### Pattern 4: Root-Level API Functions
|
|
129
95
|
|
|
130
96
|
**File**: `root-function.mjs` → **API**: `api(name)` + `api.rootFunctionShout()`
|
|
131
97
|
|
|
132
98
|
```js
|
|
133
|
-
// ✅ Root-level file creates top-level API methods
|
|
134
99
|
export default function greet(name) {
|
|
135
100
|
return `Hello, ${name}!`;
|
|
136
101
|
}
|
|
@@ -140,242 +105,358 @@ export function rootFunctionShout(message) {
|
|
|
140
105
|
}
|
|
141
106
|
```
|
|
142
107
|
|
|
143
|
-
**Result**: Root file with default export → `api()` callable + named exports as `api.methodName()
|
|
108
|
+
**Result**: Root file with default export → `api()` callable + named exports as top-level `api.methodName()`.
|
|
144
109
|
|
|
145
|
-
|
|
110
|
+
### Pattern 5: AddApi Special File Pattern (Rule 11)
|
|
146
111
|
|
|
147
|
-
|
|
112
|
+
Files named `addapi.mjs` always flatten regardless of `autoFlatten` setting:
|
|
148
113
|
|
|
149
|
-
|
|
114
|
+
```js
|
|
115
|
+
// File: plugins/addapi.mjs
|
|
116
|
+
export function initializePlugin() { return "Plugin initialized"; }
|
|
117
|
+
export function cleanup() { return "Plugin cleaned up"; }
|
|
118
|
+
```
|
|
150
119
|
|
|
151
120
|
```js
|
|
152
|
-
|
|
153
|
-
|
|
121
|
+
await api.slothlet.api.add("plugins", "./plugins-folder");
|
|
122
|
+
api.plugins.initializePlugin(); // ✅ Direct extension - no intermediate namespace
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
> 📖 See [API-RULES.md Rule 11](docs/API-RULES.md) for addApi flattening details.
|
|
154
126
|
|
|
155
|
-
|
|
156
|
-
async testCrossCall(a, b) {
|
|
157
|
-
console.log(`ESM Context: User=${context.user}`);
|
|
127
|
+
---
|
|
158
128
|
|
|
159
|
-
|
|
160
|
-
if (self?.mathCjs?.multiply) {
|
|
161
|
-
const result = self.mathCjs.multiply(a, b);
|
|
162
|
-
return result;
|
|
163
|
-
}
|
|
129
|
+
## 🔄 Operating Modes
|
|
164
130
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
131
|
+
Slothlet supports two loading modes set via `mode:` in the config:
|
|
132
|
+
|
|
133
|
+
### Eager Mode (default)
|
|
134
|
+
|
|
135
|
+
All modules are loaded synchronously at `await slothlet(...)`. The API is fully populated before `slothlet()` resolves.
|
|
136
|
+
|
|
137
|
+
```js
|
|
138
|
+
const api = await slothlet({ dir: "./api" }); // mode: "eager" is default
|
|
139
|
+
// All api.* properties are immediately available
|
|
168
140
|
```
|
|
169
141
|
|
|
170
|
-
###
|
|
142
|
+
### Lazy Mode
|
|
143
|
+
|
|
144
|
+
Modules are loaded on first access via transparent proxy. `slothlet()` resolves immediately without loading any files.
|
|
171
145
|
|
|
172
146
|
```js
|
|
173
|
-
|
|
174
|
-
const api1 = await slothlet({
|
|
147
|
+
const api = await slothlet({
|
|
175
148
|
dir: "./api",
|
|
176
|
-
|
|
149
|
+
mode: "lazy"
|
|
177
150
|
});
|
|
151
|
+
// api.math is a proxy - file not loaded yet
|
|
152
|
+
const result = api.math.add(2, 3); // First access triggers load
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
#### Background Materialization
|
|
156
|
+
|
|
157
|
+
Enable `backgroundMaterialize: true` to pre-load all modules in the background immediately after init (still non-blocking):
|
|
178
158
|
|
|
179
|
-
|
|
159
|
+
```js
|
|
160
|
+
const api = await slothlet({
|
|
180
161
|
dir: "./api",
|
|
181
|
-
|
|
162
|
+
mode: "lazy",
|
|
163
|
+
backgroundMaterialize: true
|
|
182
164
|
});
|
|
183
165
|
|
|
184
|
-
//
|
|
166
|
+
// Subscribe to completion event
|
|
167
|
+
api.slothlet.lifecycle.on("materialized:complete", (data) => {
|
|
168
|
+
console.log(`${data.total} modules materialized`);
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
// Or await all modules to be ready
|
|
172
|
+
await api.slothlet.materialize.wait();
|
|
173
|
+
|
|
174
|
+
// Or check current progress
|
|
175
|
+
const stats = api.slothlet.materialize.get();
|
|
176
|
+
// { total, materialized, remaining, percentage }
|
|
185
177
|
```
|
|
186
178
|
|
|
187
|
-
|
|
179
|
+
**Important**: Lazy mode hot reload intentionally restores modules to an unmaterialized state on reload (references are not preserved). Eager mode preserves existing references by merging into the live wrapper.
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## 🎣 Hook System
|
|
188
184
|
|
|
189
|
-
|
|
185
|
+
Hooks intercept API function calls. They work across all modes. See [`docs/HOOKS.md`](docs/HOOKS.md) for the full reference.
|
|
190
186
|
|
|
191
187
|
### Hook Configuration
|
|
192
188
|
|
|
193
189
|
```js
|
|
194
|
-
//
|
|
195
|
-
const api = await slothlet({
|
|
196
|
-
dir: "./api",
|
|
197
|
-
hooks: true // Enables all hooks with pattern "**"
|
|
198
|
-
});
|
|
190
|
+
// Simple enable (default pattern "**")
|
|
191
|
+
const api = await slothlet({ dir: "./api", hook: true });
|
|
199
192
|
|
|
200
|
-
// Enable with
|
|
193
|
+
// Enable with default pattern filter
|
|
194
|
+
const api = await slothlet({ dir: "./api", hook: "database.*" });
|
|
195
|
+
|
|
196
|
+
// Full configuration
|
|
201
197
|
const api = await slothlet({
|
|
202
198
|
dir: "./api",
|
|
203
|
-
|
|
199
|
+
hook: {
|
|
204
200
|
enabled: true,
|
|
205
201
|
pattern: "**",
|
|
206
|
-
suppressErrors:
|
|
202
|
+
suppressErrors: false // true = errors suppressed (returns undefined instead of throwing)
|
|
207
203
|
}
|
|
208
204
|
});
|
|
209
205
|
```
|
|
210
206
|
|
|
211
207
|
### Hook Types
|
|
212
208
|
|
|
213
|
-
**
|
|
214
|
-
|
|
215
|
-
- **`
|
|
216
|
-
|
|
217
|
-
- Cancel execution (short-circuit) and return custom value
|
|
218
|
-
- Validation and pre-processing
|
|
219
|
-
|
|
220
|
-
- **`after`**: Transform results after execution
|
|
221
|
-
- Transform return values
|
|
222
|
-
- Only runs if function executes
|
|
223
|
-
- Chain transformations
|
|
224
|
-
|
|
225
|
-
- **`always`**: Observe final result (read-only)
|
|
226
|
-
- Always executes (even on short-circuit)
|
|
227
|
-
- Cannot modify result
|
|
228
|
-
- Perfect for logging and metrics
|
|
229
|
-
|
|
230
|
-
- **`error`**: Monitor and handle errors
|
|
231
|
-
- Receives detailed error context
|
|
232
|
-
- Source tracking (before/function/after/always)
|
|
233
|
-
- Error class identification
|
|
209
|
+
- **`before`** - Executes before the function. Can modify arguments or short-circuit. **Must be synchronous.**
|
|
210
|
+
- **`after`** - Executes after successful completion. Can transform the return value.
|
|
211
|
+
- **`always`** - Read-only observer. Always executes (even on short-circuit). Return value ignored.
|
|
212
|
+
- **`error`** - Executes only when an error occurs. Receives error with source tracking.
|
|
234
213
|
|
|
235
214
|
### Basic Hook Usage
|
|
236
215
|
|
|
216
|
+
The `hook.on(typePattern, handler, options)` signature uses `"type:pattern"` as the first argument:
|
|
217
|
+
|
|
237
218
|
```js
|
|
238
219
|
// Before hook - modify arguments
|
|
239
|
-
api.
|
|
240
|
-
"
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
220
|
+
api.slothlet.hook.on(
|
|
221
|
+
"before:math.add",
|
|
222
|
+
({ path, args, ctx }) => {
|
|
223
|
+
return [args[0] * 2, args[1] * 2]; // Return array to replace arguments
|
|
224
|
+
// Return any non-array non-undefined value to short-circuit (skip function)
|
|
225
|
+
// Return undefined to continue with original args
|
|
245
226
|
},
|
|
246
|
-
{
|
|
227
|
+
{ id: "double-args", priority: 100 }
|
|
247
228
|
);
|
|
248
229
|
|
|
249
230
|
// After hook - transform result
|
|
250
|
-
api.
|
|
251
|
-
"
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
return result * 10; // Transform result
|
|
231
|
+
api.slothlet.hook.on(
|
|
232
|
+
"after:math.*",
|
|
233
|
+
({ path, args, result, ctx }) => {
|
|
234
|
+
return result * 10; // Return value to replace result; undefined = no change
|
|
255
235
|
},
|
|
256
|
-
{
|
|
236
|
+
{ id: "scale-result" }
|
|
257
237
|
);
|
|
258
238
|
|
|
259
239
|
// Always hook - observe (read-only)
|
|
260
|
-
api.
|
|
261
|
-
"
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
console.log(
|
|
240
|
+
api.slothlet.hook.on(
|
|
241
|
+
"always:**",
|
|
242
|
+
({ path, result, hasError, errors }) => {
|
|
243
|
+
if (hasError) console.error(`${path} failed:`, errors);
|
|
244
|
+
else console.log(`${path} returned:`, result);
|
|
245
|
+
// Return value is ignored
|
|
265
246
|
},
|
|
266
|
-
{
|
|
247
|
+
{ id: "logger" }
|
|
267
248
|
);
|
|
268
249
|
|
|
269
250
|
// Error hook - monitor failures
|
|
270
|
-
api.
|
|
271
|
-
"error
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
console.error(
|
|
275
|
-
console.error(`Error type: ${errorType}`);
|
|
251
|
+
api.slothlet.hook.on(
|
|
252
|
+
"error:**",
|
|
253
|
+
({ path, error, source }) => {
|
|
254
|
+
// source.type: "before" | "after" | "always" | "function"
|
|
255
|
+
console.error(`Error in ${path} (from ${source.type}):`, error.message);
|
|
276
256
|
},
|
|
277
|
-
{
|
|
257
|
+
{ id: "error-monitor" }
|
|
278
258
|
);
|
|
279
259
|
```
|
|
280
260
|
|
|
281
|
-
###
|
|
261
|
+
### Pattern Matching
|
|
282
262
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
263
|
+
| Syntax | Description | Example |
|
|
264
|
+
|---|---|---|
|
|
265
|
+
| `exact.path` | Exact match | `"before:math.add"` |
|
|
266
|
+
| `namespace.*` | All functions in namespace | `"after:math.*"` |
|
|
267
|
+
| `*.funcName` | Function name across namespaces | `"always:*.add"` |
|
|
268
|
+
| `**` | All functions | `"error:**"` |
|
|
269
|
+
| `{a,b}` | Brace expansion | `"before:{math,utils}.*"` |
|
|
270
|
+
| `!pattern` | Negation | `"before:!internal.*"` |
|
|
286
271
|
|
|
287
|
-
|
|
288
|
-
api.hooks.on("hook2", "before", handler, { pattern: "math.*" });
|
|
272
|
+
### Hook Subsets
|
|
289
273
|
|
|
290
|
-
|
|
291
|
-
api.hooks.on("hook3", "before", handler, { pattern: "*.add" });
|
|
292
|
-
|
|
293
|
-
// All functions
|
|
294
|
-
api.hooks.on("hook4", "before", handler, { pattern: "**" });
|
|
295
|
-
```
|
|
274
|
+
Each hook type has three ordered execution phases:
|
|
296
275
|
|
|
297
|
-
|
|
276
|
+
| Subset | Order | Typical use |
|
|
277
|
+
|---|---|---|
|
|
278
|
+
| `"before"` | First | Auth checks, security validation |
|
|
279
|
+
| `"primary"` | Middle (default) | Main hook logic |
|
|
280
|
+
| `"after"` | Last | Audit trails, cleanup |
|
|
298
281
|
|
|
299
282
|
```js
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
"
|
|
303
|
-
"before",
|
|
304
|
-
({ path, args }) => {
|
|
305
|
-
const key = JSON.stringify({ path, args });
|
|
306
|
-
if (cache.has(key)) {
|
|
307
|
-
return cache.get(key); // Skip function execution
|
|
308
|
-
}
|
|
309
|
-
// Return undefined to continue
|
|
310
|
-
},
|
|
311
|
-
{ pattern: "**", priority: 1000 }
|
|
283
|
+
api.slothlet.hook.on(
|
|
284
|
+
"before:protected.*",
|
|
285
|
+
({ ctx }) => { if (!ctx.user) throw new Error("Unauthorized"); },
|
|
286
|
+
{ id: "auth", subset: "before", priority: 2000 }
|
|
312
287
|
);
|
|
313
288
|
```
|
|
314
289
|
|
|
315
|
-
###
|
|
290
|
+
### Hook Management
|
|
291
|
+
|
|
292
|
+
```js
|
|
293
|
+
// Remove by ID
|
|
294
|
+
api.slothlet.hook.remove({ id: "my-hook" });
|
|
295
|
+
api.slothlet.hook.off("my-hook"); // alias for remove
|
|
296
|
+
|
|
297
|
+
// Remove by filter
|
|
298
|
+
api.slothlet.hook.remove({ type: "before", pattern: "math.*" });
|
|
316
299
|
|
|
317
|
-
|
|
300
|
+
// Remove all
|
|
301
|
+
api.slothlet.hook.clear();
|
|
318
302
|
|
|
319
|
-
|
|
303
|
+
// List hooks
|
|
304
|
+
const all = api.slothlet.hook.list();
|
|
305
|
+
const active = api.slothlet.hook.list({ enabled: true });
|
|
320
306
|
|
|
321
|
-
|
|
307
|
+
// Enable / disable without unregistering
|
|
308
|
+
api.slothlet.hook.disable(); // disable all
|
|
309
|
+
api.slothlet.hook.disable({ pattern: "math.*" });
|
|
310
|
+
api.slothlet.hook.enable(); // re-enable all
|
|
311
|
+
api.slothlet.hook.enable({ type: "before" });
|
|
312
|
+
```
|
|
322
313
|
|
|
323
|
-
|
|
324
|
-
- Application crashes on uncaught errors
|
|
314
|
+
---
|
|
325
315
|
|
|
326
|
-
|
|
316
|
+
## 🔄 Per-Request Context
|
|
327
317
|
|
|
328
|
-
|
|
329
|
-
- Function returns `undefined` instead of throwing
|
|
330
|
-
- All hook errors suppressed (before, after, always)
|
|
331
|
-
- Perfect for resilient systems with monitoring
|
|
318
|
+
Execute functions with temporary merged context using `api.slothlet.context`:
|
|
332
319
|
|
|
333
320
|
```js
|
|
334
321
|
const api = await slothlet({
|
|
335
322
|
dir: "./api",
|
|
336
|
-
|
|
337
|
-
enabled: true,
|
|
338
|
-
suppressErrors: true // Suppress all errors
|
|
339
|
-
}
|
|
323
|
+
context: { appName: "MyApp", version: "3.0" }
|
|
340
324
|
});
|
|
341
325
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
(
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
326
|
+
// run() - execute a function inside a scoped context
|
|
327
|
+
await api.slothlet.context.run({ userId: "alice", role: "admin" }, async () => {
|
|
328
|
+
// Inside this scope: context = { appName, version, userId, role }
|
|
329
|
+
await api.database.query();
|
|
330
|
+
await api.audit.log();
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
// scope() - return a new API object with merged context
|
|
334
|
+
const scopedApi = api.slothlet.context.scope({ userId: "bob" });
|
|
335
|
+
await scopedApi.database.query(); // context includes userId: "bob"
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
### Deep Merge Strategy
|
|
339
|
+
|
|
340
|
+
```js
|
|
341
|
+
// Default: shallow merge (top-level properties replaced)
|
|
342
|
+
await api.slothlet.context.run({ newProp: "value" }, handler);
|
|
343
|
+
|
|
344
|
+
// Deep merge: nested objects recursively merged
|
|
345
|
+
await api.slothlet.context.run(
|
|
346
|
+
{ nested: { prop: "value" } },
|
|
347
|
+
handler,
|
|
348
|
+
{ mergeStrategy: "deep" }
|
|
350
349
|
);
|
|
350
|
+
```
|
|
351
351
|
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
352
|
+
### Automatic EventEmitter Context Propagation
|
|
353
|
+
|
|
354
|
+
Context propagates automatically through EventEmitter callbacks:
|
|
355
|
+
|
|
356
|
+
```js
|
|
357
|
+
import net from "net";
|
|
358
|
+
import { context } from "@cldmv/slothlet/runtime";
|
|
359
|
+
|
|
360
|
+
export const server = {
|
|
361
|
+
async start() {
|
|
362
|
+
const tcpServer = net.createServer((socket) => {
|
|
363
|
+
// Context automatically available in connection handler
|
|
364
|
+
console.log(`User ${context.userId} connected`);
|
|
365
|
+
|
|
366
|
+
socket.on("data", (data) => {
|
|
367
|
+
// Context preserved in nested event callbacks
|
|
368
|
+
console.log(`Data from ${context.userId}: ${data}`);
|
|
369
|
+
});
|
|
370
|
+
});
|
|
371
|
+
tcpServer.listen(3000);
|
|
372
|
+
}
|
|
373
|
+
};
|
|
357
374
|
```
|
|
358
375
|
|
|
359
|
-
|
|
376
|
+
Works with: TCP servers, HTTP servers, custom EventEmitters, unlimited nested callbacks.
|
|
377
|
+
|
|
378
|
+
> 📖 See [`docs/CONTEXT-PROPAGATION.md`](docs/CONTEXT-PROPAGATION.md) for full documentation.
|
|
379
|
+
|
|
380
|
+
---
|
|
381
|
+
|
|
382
|
+
## 🏷️ Metadata System
|
|
383
|
+
|
|
384
|
+
Tag API paths with metadata for authorization, auditing, and security. See [`docs/METADATA.md`](docs/METADATA.md) for the full reference.
|
|
385
|
+
|
|
386
|
+
```js
|
|
387
|
+
// Set metadata when loading (via api.slothlet.api.add)
|
|
388
|
+
await api.slothlet.api.add("plugins/trusted", "./trusted-dir", {
|
|
389
|
+
metadata: { trusted: true, securityLevel: "high" }
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
// Set metadata at runtime
|
|
393
|
+
api.slothlet.metadata.set("plugins.trusted.someFunc", { version: 2 });
|
|
394
|
+
api.slothlet.metadata.setGlobal({ environment: "production" });
|
|
395
|
+
api.slothlet.metadata.setFor("plugins/trusted", { owner: "core-team" });
|
|
396
|
+
|
|
397
|
+
// Read metadata inside a module
|
|
398
|
+
import { self } from "@cldmv/slothlet/runtime";
|
|
399
|
+
|
|
400
|
+
export const secureOperation = {
|
|
401
|
+
async execute() {
|
|
402
|
+
// Access metadata via api.slothlet.metadata from within a module via self
|
|
403
|
+
// Or read it externally:
|
|
404
|
+
// const meta = api.slothlet.metadata.get("plugins.trusted.execute");
|
|
405
|
+
return "Authorized execution";
|
|
406
|
+
}
|
|
407
|
+
};
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
---
|
|
411
|
+
|
|
412
|
+
## 🔁 Hot Reload / Dynamic API Management
|
|
360
413
|
|
|
361
414
|
```js
|
|
362
|
-
//
|
|
363
|
-
|
|
415
|
+
// Add new modules at runtime
|
|
416
|
+
await api.slothlet.api.add("newModule", "./new-module-path");
|
|
417
|
+
await api.slothlet.api.add("plugins", "./plugins", { collision: "merge" });
|
|
418
|
+
|
|
419
|
+
// Remove modules by path
|
|
420
|
+
await api.slothlet.api.remove("oldModule");
|
|
421
|
+
|
|
422
|
+
// Reload all modules
|
|
423
|
+
await api.slothlet.reload();
|
|
424
|
+
|
|
425
|
+
// Reload specific API path
|
|
426
|
+
await api.slothlet.api.reload("database.*");
|
|
427
|
+
await api.slothlet.api.reload("plugins.auth");
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
> **Lazy mode reload behavior**: In lazy mode, reload restores modules to an unmaterialized proxy state - existing references to lazy wrappers are intentionally not preserved. Eager mode merges new module exports into the existing live wrapper, preserving references.
|
|
431
|
+
|
|
432
|
+
> 📖 See [`docs/RELOAD.md`](docs/RELOAD.md) for reload system documentation.
|
|
433
|
+
|
|
434
|
+
---
|
|
364
435
|
|
|
365
|
-
|
|
366
|
-
api.hooks.off(hookId);
|
|
436
|
+
## ⚡ Lifecycle Events
|
|
367
437
|
|
|
368
|
-
|
|
369
|
-
api.hooks.clear();
|
|
438
|
+
Subscribe to internal API events via `api.slothlet.lifecycle`:
|
|
370
439
|
|
|
371
|
-
|
|
372
|
-
|
|
440
|
+
```js
|
|
441
|
+
// Available events
|
|
442
|
+
api.slothlet.lifecycle.on("materialized:complete", (data) => {
|
|
443
|
+
console.log(`${data.total} modules materialized`);
|
|
444
|
+
});
|
|
373
445
|
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
446
|
+
api.slothlet.lifecycle.on("impl:changed", (data) => {
|
|
447
|
+
console.log(`Module at ${data.apiPath} was reloaded`);
|
|
448
|
+
});
|
|
449
|
+
|
|
450
|
+
// Unsubscribe
|
|
451
|
+
const handler = (data) => console.log(data);
|
|
452
|
+
api.slothlet.lifecycle.on("materialized:complete", handler);
|
|
453
|
+
api.slothlet.lifecycle.off("materialized:complete", handler);
|
|
377
454
|
```
|
|
378
455
|
|
|
456
|
+
**Available events**: `"materialized:complete"`, `"impl:created"`, `"impl:changed"`, `"impl:removed"`
|
|
457
|
+
|
|
458
|
+
---
|
|
459
|
+
|
|
379
460
|
## 📁 File Organization Best Practices
|
|
380
461
|
|
|
381
462
|
### ✅ Clean Folder Structure
|
|
@@ -384,7 +465,7 @@ api.hooks.enable("database.*"); // Re-enable with new pattern
|
|
|
384
465
|
api/
|
|
385
466
|
├── config.mjs → api.config.*
|
|
386
467
|
├── math/
|
|
387
|
-
│ └── math.mjs → api.math.* (flattened)
|
|
468
|
+
│ └── math.mjs → api.math.* (flattened - filename matches folder)
|
|
388
469
|
├── util/
|
|
389
470
|
│ ├── util.mjs → api.util.* (flattened methods)
|
|
390
471
|
│ ├── extract.mjs → api.util.extract.*
|
|
@@ -397,140 +478,130 @@ api/
|
|
|
397
478
|
└── beta.mjs → api.multi.beta.*
|
|
398
479
|
```
|
|
399
480
|
|
|
400
|
-
### ✅
|
|
481
|
+
### ✅ Naming Conventions
|
|
401
482
|
|
|
402
|
-
- **Filename matches folder** → Auto-flattening (
|
|
483
|
+
- **Filename matches folder** → Auto-flattening (`math/math.mjs` → `api.math.*`)
|
|
403
484
|
- **Different filename** → Nested structure preserved
|
|
404
485
|
- **Dash-separated names** → camelCase API (`auto-ip.mjs` → `api.autoIP`)
|
|
405
|
-
- **Function name
|
|
406
|
-
|
|
407
|
-
## 🧪 JSDoc Documentation Patterns
|
|
408
|
-
|
|
409
|
-
> 📖 **For detailed JSDoc templates and examples**, see [.github/copilot-instructions.md - JSDoc Standards](./.github/copilot-instructions.md#-jsdoc-standards--patterns)
|
|
486
|
+
- **Function name preferred** → Original capitalization kept over sanitized form
|
|
487
|
+
(see [Rule 9](docs/API-RULES.md))
|
|
410
488
|
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
```js
|
|
414
|
-
/**
|
|
415
|
-
* @fileoverview Math operations for API testing.
|
|
416
|
-
* @module api_test
|
|
417
|
-
* @name api_test
|
|
418
|
-
* @alias @cldmv/slothlet/api_tests/api_test
|
|
419
|
-
*/
|
|
420
|
-
```
|
|
421
|
-
|
|
422
|
-
### ✅ Secondary Contributing Files
|
|
423
|
-
|
|
424
|
-
```js
|
|
425
|
-
/**
|
|
426
|
-
* @fileoverview Math utilities. Internal file (not exported in package.json).
|
|
427
|
-
* @module api_test.math
|
|
428
|
-
* @memberof module:api_test
|
|
429
|
-
*/
|
|
430
|
-
```
|
|
431
|
-
|
|
432
|
-
### ✅ Live-Binding Imports Pattern
|
|
433
|
-
|
|
434
|
-
```js
|
|
435
|
-
// ✅ Always include runtime imports (even if commented out for structure)
|
|
436
|
-
// import { self, context, reference } from "@cldmv/slothlet/runtime";
|
|
437
|
-
```
|
|
489
|
+
---
|
|
438
490
|
|
|
439
491
|
## 🚨 Common AI Agent Mistakes
|
|
440
492
|
|
|
441
|
-
> 📖 **For complete technical details on all API transformation rules**, see [API-RULES.md](./API-RULES.md) (778+ lines of verified examples)
|
|
442
|
-
|
|
443
493
|
### ❌ Mistake 1: Cross-Module Imports
|
|
444
494
|
|
|
445
495
|
```js
|
|
446
496
|
// ❌ WRONG
|
|
447
497
|
import { config } from "./config.mjs";
|
|
498
|
+
// ✅ CORRECT
|
|
499
|
+
import { self } from "@cldmv/slothlet/runtime";
|
|
500
|
+
// then: self.config.get(...)
|
|
448
501
|
```
|
|
449
502
|
|
|
450
|
-
### ❌ Mistake 2:
|
|
503
|
+
### ❌ Mistake 2: Using V2 API Surface
|
|
451
504
|
|
|
452
505
|
```js
|
|
453
|
-
// ❌ WRONG -
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
506
|
+
// ❌ WRONG (v2 API - does not exist in v3)
|
|
507
|
+
await api.addApi("plugins", "./dir");
|
|
508
|
+
await api.reloadApi("math.*");
|
|
509
|
+
api.hooks.on("validate", "before", handler, { pattern: "math.*" });
|
|
510
|
+
await api.run({ userId: "alice" }, fn);
|
|
511
|
+
|
|
512
|
+
// ✅ CORRECT (v3 API)
|
|
513
|
+
await api.slothlet.api.add("plugins", "./dir");
|
|
514
|
+
await api.slothlet.api.reload("math.*");
|
|
515
|
+
api.slothlet.hook.on("before:math.*", handler);
|
|
516
|
+
await api.slothlet.context.run({ userId: "alice" }, fn);
|
|
459
517
|
```
|
|
460
518
|
|
|
461
|
-
### ❌ Mistake 3: Wrong
|
|
519
|
+
### ❌ Mistake 3: Wrong Hook Config Key
|
|
462
520
|
|
|
463
521
|
```js
|
|
464
|
-
// ❌ WRONG
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
522
|
+
// ❌ WRONG
|
|
523
|
+
const api = await slothlet({ dir: "./api", hooks: true }); // "hooks" plural
|
|
524
|
+
|
|
525
|
+
// ✅ CORRECT
|
|
526
|
+
const api = await slothlet({ dir: "./api", hook: true }); // "hook" singular
|
|
469
527
|
```
|
|
470
528
|
|
|
471
529
|
### ❌ Mistake 4: Breaking Auto-Flattening
|
|
472
530
|
|
|
473
531
|
```js
|
|
474
|
-
// File: math/calculator.mjs
|
|
475
|
-
export const math = {
|
|
476
|
-
|
|
477
|
-
};
|
|
478
|
-
// Result: api.math.calculator.math.* (nested, not flattened)
|
|
532
|
+
// File: math/calculator.mjs (different name from folder)
|
|
533
|
+
export const math = { /* methods */ };
|
|
534
|
+
// Result: api.math.calculator.math.* ← extra nesting, not flattened
|
|
479
535
|
|
|
480
536
|
// ✅ CORRECT: File math/math.mjs
|
|
481
|
-
export const math = {
|
|
482
|
-
|
|
483
|
-
};
|
|
484
|
-
// Result: api.math.* (flattened)
|
|
537
|
+
export const math = { /* methods */ };
|
|
538
|
+
// Result: api.math.* ← flattened
|
|
485
539
|
```
|
|
486
540
|
|
|
487
|
-
|
|
541
|
+
### ❌ Mistake 5: Using lifecycle.subscribe / lifecycle.emit
|
|
542
|
+
|
|
543
|
+
```js
|
|
544
|
+
// ❌ WRONG - subscribe/emit are internal
|
|
545
|
+
api.slothlet.lifecycle.subscribe("materialized:complete", handler);
|
|
546
|
+
api.slothlet.lifecycle.emit("impl:changed", data);
|
|
547
|
+
|
|
548
|
+
// ✅ CORRECT - public surface is on/off only
|
|
549
|
+
api.slothlet.lifecycle.on("materialized:complete", handler);
|
|
550
|
+
api.slothlet.lifecycle.off("materialized:complete", handler);
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
---
|
|
488
554
|
|
|
489
|
-
|
|
555
|
+
## ✅ AI Agent Checklist
|
|
490
556
|
|
|
491
|
-
- [ ] **
|
|
492
|
-
- [ ] **Import runtime** - `import { self, context, reference } from "@cldmv/slothlet/runtime"`
|
|
557
|
+
- [ ] **No cross-module imports** - use `self` from `@cldmv/slothlet/runtime` instead
|
|
493
558
|
- [ ] **Match filename to folder** for cleaner APIs (auto-flattening)
|
|
494
|
-
- [ ] **
|
|
495
|
-
- [ ] **
|
|
496
|
-
- [ ] **
|
|
497
|
-
- [ ] **
|
|
498
|
-
- [ ] **
|
|
559
|
+
- [ ] **Hook config key is `hook:` (singular)**, not `hooks:`
|
|
560
|
+
- [ ] **Hook API** is `api.slothlet.hook.*`, not `api.hooks.*`
|
|
561
|
+
- [ ] **Context API** is `api.slothlet.context.run/scope()`, not `api.run/scope()`
|
|
562
|
+
- [ ] **Reload/add/remove** is `api.slothlet.api.add/remove/reload()`, not `api.addApi()` etc.
|
|
563
|
+
- [ ] **Lifecycle** uses `api.slothlet.lifecycle.on/off()` only
|
|
564
|
+
- [ ] **Lazy mode**: if using background materialization, use `api.slothlet.materialize.wait()` before accessing the API
|
|
565
|
+
- [ ] **Hook subsets**: auth/security → `subset: "before"`, main logic → `"primary"`, audit → `"after"`
|
|
566
|
+
- [ ] **Double quotes everywhere** - follow Slothlet coding standards
|
|
567
|
+
|
|
568
|
+
---
|
|
499
569
|
|
|
500
570
|
## 📚 Reference Examples
|
|
501
571
|
|
|
502
572
|
- **Auto-flattening**: `api_tests/api_test/math/math.mjs`
|
|
503
573
|
- **Multi-file folders**: `api_tests/api_test/multi/`
|
|
504
|
-
- **Cross-module calls**: `api_tests/api_test_mixed
|
|
574
|
+
- **Cross-module calls**: `api_tests/api_test_mixed/`
|
|
505
575
|
- **Root-level APIs**: `api_tests/api_test/root-function.mjs`
|
|
506
576
|
- **Nested structures**: `api_tests/api_test/nested/date/`
|
|
507
577
|
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
### 🏗️ **Core Architecture & Patterns**
|
|
511
|
-
|
|
512
|
-
- **[`API-RULES.md`](./API-RULES.md)** - **CRITICAL** - Comprehensive verified rules for API transformation (778+ lines of verified examples)
|
|
513
|
-
- **[`API-RULES-CONDITIONS.md`](./API-RULES-CONDITIONS.md)** - Technical reference for all conditional logic controlling API generation
|
|
514
|
-
|
|
515
|
-
### � **Usage & Installation**
|
|
516
|
-
|
|
517
|
-
- **[`README.md`](./README.md)** - Complete project overview, installation, and usage examples
|
|
578
|
+
---
|
|
518
579
|
|
|
519
|
-
|
|
580
|
+
## 📖 Essential Documentation
|
|
520
581
|
|
|
521
|
-
|
|
522
|
-
- **[`api_tests/api_test_cjs/README.md`](./api_tests/api_test_cjs/)** - CommonJS module patterns and interoperability
|
|
523
|
-
- **[`api_tests/api_test_mixed/README.md`](./api_tests/api_test_mixed/)** - Mixed ESM/CJS patterns and live-binding examples
|
|
582
|
+
### Core Architecture
|
|
524
583
|
|
|
525
|
-
|
|
584
|
+
- **[`docs/API-RULES.md`](docs/API-RULES.md)** - All 13 API transformation rules
|
|
585
|
+
- **[`docs/API-RULES/API-RULES-CONDITIONS.md`](docs/API-RULES/API-RULES-CONDITIONS.md)** - All C01–C34 conditional logic
|
|
586
|
+
- **[`docs/API-RULES/API-FLATTENING.md`](docs/API-RULES/API-FLATTENING.md)** - Flattening rules F01–F08
|
|
526
587
|
|
|
527
|
-
|
|
588
|
+
### Configuration & Features
|
|
528
589
|
|
|
529
|
-
|
|
590
|
+
- **[`docs/CONFIGURATION.md`](docs/CONFIGURATION.md)** - All config options
|
|
591
|
+
- **[`docs/HOOKS.md`](docs/HOOKS.md)** - Hook system (types, subsets, patterns, management)
|
|
592
|
+
- **[`docs/METADATA.md`](docs/METADATA.md)** - Metadata system
|
|
593
|
+
- **[`docs/CONTEXT-PROPAGATION.md`](docs/CONTEXT-PROPAGATION.md)** - Per-request context and EventEmitter propagation
|
|
594
|
+
- **[`docs/RELOAD.md`](docs/RELOAD.md)** - Hot reload and dynamic API management
|
|
595
|
+
- **[`docs/LIFECYCLE.md`](docs/LIFECYCLE.md)** - Lazy mode, materialization, and lifecycle events
|
|
596
|
+
- **[`docs/SANITIZATION.md`](docs/SANITIZATION.md)** - Property name sanitization rules
|
|
597
|
+
- **[`docs/I18N.md`](docs/I18N.md)** - Internationalization and language support
|
|
598
|
+
- **[`docs/PERFORMANCE.md`](docs/PERFORMANCE.md)** - Performance characteristics and benchmarks
|
|
530
599
|
|
|
531
|
-
|
|
532
|
-
2. **[`README.md`](./README.md)** - Complete project context and installation
|
|
533
|
-
3. **[`API-RULES.md`](./API-RULES.md)** - Understand verified API transformation patterns
|
|
534
|
-
4. **[`api_tests/*/README.md`](./api_tests/)** - Live examples of each pattern
|
|
600
|
+
### Critical Reading Order for AI Agents
|
|
535
601
|
|
|
536
|
-
|
|
602
|
+
1. **This file** - Prevents architectural mistakes
|
|
603
|
+
2. **[`README.md`](README.md)** - Project overview and quickstart
|
|
604
|
+
3. **[`docs/API-RULES.md`](docs/API-RULES.md)** - API transformation rules
|
|
605
|
+
4. **[`docs/HOOKS.md`](docs/HOOKS.md)** - Hook system (if needed)
|
|
606
|
+
5. **[`docs/METADATA.md`](docs/METADATA.md)** - Metadata system (if needed)
|
|
607
|
+
6. **[`api_tests/api_test/README.md`](api_tests/api_test/README.md)** - Live examples
|