@cldmv/slothlet 2.8.0 → 2.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/AGENT-USAGE.md +1 -1
  2. package/README.md +300 -1557
  3. package/dist/lib/engine/slothlet_child.mjs +1 -1
  4. package/dist/lib/engine/slothlet_engine.mjs +1 -1
  5. package/dist/lib/engine/slothlet_esm.mjs +1 -1
  6. package/dist/lib/engine/slothlet_helpers.mjs +1 -1
  7. package/dist/lib/engine/slothlet_worker.mjs +1 -1
  8. package/dist/lib/helpers/als-eventemitter.mjs +5 -6
  9. package/dist/lib/helpers/api_builder/add_api.mjs +292 -0
  10. package/dist/lib/helpers/api_builder/analysis.mjs +532 -0
  11. package/dist/lib/helpers/api_builder/construction.mjs +457 -0
  12. package/dist/lib/helpers/api_builder/decisions.mjs +737 -0
  13. package/dist/lib/helpers/api_builder/metadata.mjs +248 -0
  14. package/dist/lib/helpers/api_builder.mjs +17 -1568
  15. package/dist/lib/helpers/auto-wrap.mjs +1 -1
  16. package/dist/lib/helpers/hooks.mjs +1 -1
  17. package/dist/lib/helpers/instance-manager.mjs +1 -1
  18. package/dist/lib/helpers/metadata-api.mjs +201 -0
  19. package/dist/lib/helpers/multidefault.mjs +12 -3
  20. package/dist/lib/helpers/resolve-from-caller.mjs +1 -1
  21. package/dist/lib/helpers/sanitize.mjs +1 -1
  22. package/dist/lib/helpers/utilities.mjs +121 -0
  23. package/dist/lib/modes/slothlet_eager.mjs +1 -1
  24. package/dist/lib/modes/slothlet_lazy.mjs +10 -1
  25. package/dist/lib/runtime/runtime-asynclocalstorage.mjs +49 -18
  26. package/dist/lib/runtime/runtime-livebindings.mjs +23 -4
  27. package/dist/lib/runtime/runtime.mjs +15 -4
  28. package/dist/slothlet.mjs +164 -748
  29. package/docs/API-RULES-CONDITIONS.md +508 -0
  30. package/{API-RULES.md → docs/API-RULES.md} +127 -72
  31. package/package.json +11 -9
  32. package/types/dist/lib/helpers/als-eventemitter.d.mts.map +1 -1
  33. package/types/dist/lib/helpers/api_builder/add_api.d.mts +76 -0
  34. package/types/dist/lib/helpers/api_builder/add_api.d.mts.map +1 -0
  35. package/types/dist/lib/helpers/api_builder/analysis.d.mts +189 -0
  36. package/types/dist/lib/helpers/api_builder/analysis.d.mts.map +1 -0
  37. package/types/dist/lib/helpers/api_builder/construction.d.mts +107 -0
  38. package/types/dist/lib/helpers/api_builder/construction.d.mts.map +1 -0
  39. package/types/dist/lib/helpers/api_builder/decisions.d.mts +213 -0
  40. package/types/dist/lib/helpers/api_builder/decisions.d.mts.map +1 -0
  41. package/types/dist/lib/helpers/api_builder/metadata.d.mts +99 -0
  42. package/types/dist/lib/helpers/api_builder/metadata.d.mts.map +1 -0
  43. package/types/dist/lib/helpers/api_builder.d.mts +5 -448
  44. package/types/dist/lib/helpers/api_builder.d.mts.map +1 -1
  45. package/types/dist/lib/helpers/metadata-api.d.mts +132 -0
  46. package/types/dist/lib/helpers/metadata-api.d.mts.map +1 -0
  47. package/types/dist/lib/helpers/multidefault.d.mts.map +1 -1
  48. package/types/dist/lib/helpers/utilities.d.mts +120 -0
  49. package/types/dist/lib/helpers/utilities.d.mts.map +1 -0
  50. package/types/dist/lib/runtime/runtime-asynclocalstorage.d.mts +9 -0
  51. package/types/dist/lib/runtime/runtime-asynclocalstorage.d.mts.map +1 -1
  52. package/types/dist/lib/runtime/runtime-livebindings.d.mts +10 -0
  53. package/types/dist/lib/runtime/runtime-livebindings.d.mts.map +1 -1
  54. package/types/dist/lib/runtime/runtime.d.mts +1 -0
  55. package/types/dist/lib/runtime/runtime.d.mts.map +1 -1
  56. package/types/dist/slothlet.d.mts +0 -11
  57. package/types/dist/slothlet.d.mts.map +1 -1
  58. package/types/index.d.mts +0 -1
  59. package/API-RULES-CONDITIONS.md +0 -367
@@ -1,6 +1,9 @@
1
1
  # Slothlet API Rules - Verified Documentation
2
2
 
3
3
  > **Verification Status**: Each rule has been systematically verified against actual test files and source code.
4
+ > **Last Updated**: December 30, 2025
5
+ > **Commit**: `a50531d1ba712f0c4efd9ab9b7cf8f62a0d379da`
6
+ > **Note**: Source code has been refactored into modular structure. See [API-RULES-CONDITIONS.md](API-RULES-CONDITIONS.md) for complete conditional logic documentation with exact line numbers.
4
7
 
5
8
  ## Methodology
6
9
 
@@ -26,7 +29,7 @@ Each rule documents:
26
29
  - [x] Rule 9: Function Name Preference Over Sanitization ✅ **FULLY VERIFIED** (Multiple examples verified: autoIP, parseJSON, getHTTPStatus, XMLParser)
27
30
  - [x] Rule 10: Generic Filename Parent-Level Promotion ✅ **VERIFIED** (nest4/singlefile.mjs example verified with api_tests/api_test)
28
31
 
29
- > **Note**: Rule 11 (Single File Context Flattening) has been **intentionally removed** from slothlet for architectural reasons. The rule reduced API path flexibility and was commented out in source code (api_builder.mjs lines 618-626, multidefault.mjs lines 212-216). This maintains cleaner API namespacing while preserving predictable path structures.
32
+ > **Note**: Rule 11 (Single File Context Flattening) has been **intentionally removed** from slothlet for architectural reasons. The rule reduced API path flexibility and was commented out in source code. See [C06](API-RULES-CONDITIONS.md#c06-single-file-context-commented-out) in API-RULES-CONDITIONS.md for details. This maintains cleaner API namespacing while preserving predictable path structures.
30
33
 
31
34
  ---
32
35
 
@@ -72,12 +75,14 @@ node tests/debug-slothlet.mjs
72
75
  # Confirms flattening works: api.math.add (not api.math.math.add)
73
76
  ```
74
77
 
75
- **Source Code Location**: `src/lib/helpers/api_builder.mjs` line 607 - `getFlatteningDecision` function
76
- **Git Commit**: `c2f081a321c738f86196fdfdb19b6a5a706022ef`
78
+ **Source Code Location**: `src/lib/helpers/api_builder/decisions.mjs` - `getFlatteningDecision()` function [Lines 87-189](../src/lib/helpers/api_builder/decisions.mjs#L87-L189)
79
+ **Git Commit**: `a50531d1ba712f0c4efd9ab9b7cf8f62a0d379da`
80
+ **Specific Condition**: See [C05](API-RULES-CONDITIONS.md#c05-filename-matches-container-category-level-flatten) in API-RULES-CONDITIONS.md
77
81
  **Technical Implementation**:
78
82
 
79
83
  ```javascript
80
- // Rule 4: Filename matches container - flatten to container level
84
+ // C05: Filename Matches Container (Category-Level Flatten)
85
+ // Location: src/lib/helpers/api_builder/decisions.mjs Line 154
81
86
  if (categoryName && fileName === categoryName && !moduleHasDefault && moduleKeys.length > 0) {
82
87
  return {
83
88
  shouldFlatten: true,
@@ -121,8 +126,9 @@ api.config.username; // → "admin"
121
126
  api.config.secure; // → true
122
127
  ```
123
128
 
124
- **Source Code Location**: `src/lib/helpers/api_builder.mjs` lines 810-812 - `processModuleForAPI` function
125
- **Git Commit**: `c2f081a321c738f86196fdfdb19b6a5a706022ef`
129
+ **Source Code Location**: `src/lib/helpers/api_builder/decisions.mjs` - `processModuleForAPI()` function [Lines 315-466](../src/lib/helpers/api_builder/decisions.mjs#L315-L466)
130
+ **Git Commit**: `a50531d1ba712f0c4efd9ab9b7cf8f62a0d379da`
131
+ **Specific Condition**: See [C09b](API-RULES-CONDITIONS.md#c09b-flatten-to-rootcategory) in API-RULES-CONDITIONS.md
126
132
  **Technical Implementation**:
127
133
 
128
134
  ```javascript
@@ -151,8 +157,8 @@ node tests/debug-slothlet.mjs
151
157
  **Status**: ✅ **VERIFIED**
152
158
 
153
159
  **Condition**: Folders with no module files (`moduleFiles.length === 0`)
154
- **Source Code Location**: `src/lib/helpers/api_builder.mjs` lines 318-319
155
- **Git Commit**: `c2f081a321c738f86196fdfdb19b6a5a706022ef`
160
+ **Source Code Location**: `src/slothlet.mjs` [Lines 318-319](../src/slothlet.mjs#L318-L319)
161
+ **Git Commit**: `a50531d1ba712f0c4efd9ab9b7cf8f62a0d379da`
156
162
  **Processing Path**: All paths (detected in `analyzeDirectoryStructure`)
157
163
 
158
164
  **Verified Example**:
@@ -182,10 +188,10 @@ node tests/debug-slothlet.mjs
182
188
 
183
189
  **Technical Details**:
184
190
 
185
- - **Detection**: `analyzeDirectoryStructure` sets `processingStrategy = "empty"` when `moduleFiles.length === 0`
186
- - **Source Code**: `src/lib/helpers/api_builder.mjs` lines 318-319
191
+ - **Detection**: `analyzeDirectoryStructure` in `src/lib/helpers/api_builder/analysis.mjs` detects empty directories
187
192
  - **Handling**: Empty `processedModules` and `subDirectories` arrays result in empty object
188
193
  - **API Result**: Empty folder becomes empty object property on API
194
+ - **Implementation**: See `buildCategoryStructure()` in `src/lib/helpers/api_builder/construction.mjs`
189
195
 
190
196
  ---
191
197
 
@@ -195,8 +201,9 @@ node tests/debug-slothlet.mjs
195
201
 
196
202
  **Condition**: When a module has a default export (function or object)
197
203
  **Behavior**: Default export becomes the container callable/content, named exports spread to same level
198
- **Source Code**: `src/lib/helpers/api_builder.mjs` lines 246-255 + 747-757 + 318-319
199
- **Git Commit**: `c2f081a321c738f86196fdfdb19b6a5a706022ef`
204
+ **Source Code**: `processModuleForAPI()` in `src/lib/helpers/api_builder/decisions.mjs` [L315-466](../src/lib/helpers/api_builder/decisions.mjs#L315-L466)
205
+ **Detailed Conditions**: See [C08 (Has Default Function Export)](API-RULES-CONDITIONS.md#c08-has-default-function-export) in API-RULES-CONDITIONS.md
206
+ **Git Commit**: `a50531d1ba712f0c4efd9ab9b7cf8f62a0d379da`
200
207
 
201
208
  **Pattern A: Default Function + Named Exports**:
202
209
 
@@ -251,14 +258,17 @@ api.funcmod("World"); // → "Hello, World!" (default export becomes namespaced
251
258
  **Technical Implementation**:
252
259
 
253
260
  ```javascript
254
- // Lines 747-757 in processModuleForAPI()
261
+ // C08c: Traditional Default Function - Root API
262
+ // src/lib/helpers/api_builder/decisions.mjs Line 378
255
263
  if (mode === "root" && getRootDefault && setRootDefault && !hasMultipleDefaultExports && !getRootDefault()) {
256
264
  // Root context: Make API itself callable
257
265
  setRootDefault(defaultFunction);
258
- // Named exports are already attached as properties
266
+ rootDefaultSet = true;
259
267
  } else {
260
- // Subfolder context: Create namespaced callable
268
+ // C08d: Function As Namespace (Subfolder context)
269
+ // Line 384+
261
270
  apiAssignments[apiPathKey] = mod;
271
+ namespaced = true;
262
272
  }
263
273
  ```
264
274
 
@@ -282,8 +292,9 @@ node -e "const slothlet = await import('./index.mjs'); const api = await slothle
282
292
 
283
293
  **Condition**: When a container has MULTIPLE files with default exports
284
294
  **Behavior**: Files with defaults become namespaces, files without defaults flatten to container level
285
- **Source Code**: `src/lib/helpers/multidefault.mjs` lines 177-196
286
- **Git Commit**: `c2f081a321c738f86196fdfdb19b6a5a706022ef`
295
+ **Source Code**: `multidefault_getFlatteningDecision()` in `src/lib/helpers/multidefault.mjs` [L178-262](../src/lib/helpers/multidefault.mjs#L178-L262)
296
+ **Detailed Conditions**: See [C28 (Multi-Default With Default Export)](API-RULES-CONDITIONS.md#c28-multi-default-with-default-export) and [C29 (Multi-Default Without Default Export)](API-RULES-CONDITIONS.md#c29-multi-default-without-default-export) in API-RULES-CONDITIONS.md
297
+ **Git Commit**: `a50531d1ba712f0c4efd9ab9b7cf8f62a0d379da`
287
298
 
288
299
  **Example: api_tv_test folder demonstrates both patterns**:
289
300
 
@@ -316,24 +327,26 @@ api.disconnect(); // from connection.mjs
316
327
  **Technical Implementation**:
317
328
 
318
329
  ```javascript
319
- // Lines 177-186: Files WITH default exports become namespaces
320
- if (moduleHasDefault) {
321
- return {
322
- shouldFlatten: false,
323
- flattenToRoot: false,
324
- preserveAsNamespace: true,
325
- reason: "multi-default context with default export"
326
- };
327
- }
330
+ // C28: Multi-Default With Default Export
331
+ // src/lib/helpers/multidefault.mjs Line 210-211
332
+ if (hasMultipleDefaultExports) {
333
+ if (moduleHasDefault) {
334
+ return {
335
+ shouldFlatten: false,
336
+ preserveAsNamespace: true,
337
+ reason: "multi-default context with default export"
338
+ };
339
+ }
328
340
 
329
- // Lines 189-196: Files WITHOUT default exports flatten to container
330
- else {
331
- return {
332
- shouldFlatten: true,
333
- flattenToRoot: true,
334
- preserveAsNamespace: false,
335
- reason: "multi-default context without default export"
336
- };
341
+ // C29: Multi-Default Without Default Export
342
+ // Line 219
343
+ else {
344
+ return {
345
+ shouldFlatten: true,
346
+ flattenToRoot: true,
347
+ reason: "multi-default context without default export"
348
+ };
349
+ }
337
350
  }
338
351
  ```
339
352
 
@@ -354,8 +367,8 @@ node -e "const slothlet = await import('./index.mjs'); const api = await slothle
354
367
 
355
368
  **Condition**: When filename matches an exported property name (creates potential infinite nesting)
356
369
  **Behavior**: Always preserve as namespace to avoid `api.config.config.config...` infinite loops
357
- **Source Code Conditions**: C01, C08b, C09c, C19, C21 (5 implementations across all processing paths)
358
- **Git Commit**: `c2f081a321c738f86196fdfdb19b6a5a706022ef`
370
+ **Source Code Conditions**: [C01](API-RULES-CONDITIONS.md#c01-self-referential-check), [C08b](API-RULES-CONDITIONS.md#c08b-self-referential-function), [C09c](API-RULES-CONDITIONS.md#c09c-self-referential-non-function), [C20](API-RULES-CONDITIONS.md#c20-multi-file-self-referential), [C27](API-RULES-CONDITIONS.md#c27-multi-default-self-referential) (5 implementations)
371
+ **Git Commit**: `a50531d1ba712f0c4efd9ab9b7cf8f62a0d379da`
359
372
 
360
373
  **Verified Examples**:
361
374
 
@@ -386,7 +399,7 @@ node -e "const slothlet = await import('./index.mjs'); const api = await slothle
386
399
  **Technical Implementation** (5 locations):
387
400
 
388
401
  ```javascript
389
- // C01: getFlatteningDecision() - line 558
402
+ // C01: getFlatteningDecision() - decisions.mjs Line 105
390
403
  if (isSelfReferential) {
391
404
  return {
392
405
  shouldFlatten: false,
@@ -395,25 +408,24 @@ if (isSelfReferential) {
395
408
  };
396
409
  }
397
410
 
398
- // C08b: processModuleForAPI() function exports - line 728
411
+ // C08b: processModuleForAPI() function exports - decisions.mjs Line 361
399
412
  else if (isSelfReferential) {
400
413
  apiAssignments[apiPathKey] = mod;
401
414
  namespaced = true;
402
415
  }
403
416
 
404
- // C09c: processModuleForAPI() non-function exports - line 797
417
+ // C09c: processModuleForAPI() non-function exports - decisions.mjs Line 440
405
418
  else if (isSelfReferential) {
406
419
  apiAssignments[apiPathKey] = mod[apiPathKey] || mod;
407
420
  namespaced = true;
408
421
  }
409
422
 
410
- // C19: buildCategoryDecisions() multi-file - line 1712
423
+ // C20: buildCategoryDecisions() multi-file - decisions.mjs Line 846
411
424
  else if (selfReferentialFiles.has(moduleName)) {
412
425
  moduleDecision.type = "self-referential";
413
- moduleDecision.specialHandling = "self-referential-namespace";
414
426
  }
415
427
 
416
- // C21: multidefault_getFlatteningDecision() - line 168
428
+ // C27: multidefault_getFlatteningDecision() - multidefault.mjs Line 199
417
429
  if (isSelfReferential) {
418
430
  return {
419
431
  shouldFlatten: false,
@@ -441,8 +453,8 @@ node tests/debug-slothlet.mjs
441
453
 
442
454
  **Condition**: Module exports single named export that matches sanitized filename
443
455
  **Behavior**: Use the export contents directly instead of wrapping in namespace
444
- **Source Code Conditions**: C04, C16, C20c, C24 (4 implementations across processing contexts)
445
- **Git Commit**: `c2f081a321c738f86196fdfdb19b6a5a706022ef`
456
+ **Source Code Conditions**: [C04](API-RULES-CONDITIONS.md#c04-auto-flatten-single-named-export-matching-filename), [C18](API-RULES-CONDITIONS.md#c18-single-named-export-match-secondary-check), [C21c](API-RULES-CONDITIONS.md#c21c-single-named-export-match), [C30](API-RULES-CONDITIONS.md#c30-single-named-export-match) (4 implementations)
457
+ **Git Commit**: `a50531d1ba712f0c4efd9ab9b7cf8f62a0d379da`
446
458
 
447
459
  **Verified Examples**:
448
460
 
@@ -473,7 +485,7 @@ node -e "(async () => { const slothlet = await import('./index.mjs'); const api
473
485
  **Technical Implementation** (4 locations):
474
486
 
475
487
  ```javascript
476
- // C04: getFlatteningDecision() - line 593
488
+ // C04: getFlatteningDecision() - decisions.mjs Line 142
477
489
  if (moduleKeys.length === 1 && moduleKeys[0] === apiPathKey) {
478
490
  return {
479
491
  shouldFlatten: true,
@@ -482,21 +494,25 @@ if (moduleKeys.length === 1 && moduleKeys[0] === apiPathKey) {
482
494
  };
483
495
  }
484
496
 
485
- // C16: buildCategoryStructure() single-file - line 1063
497
+ // C18: buildCategoryDecisions() - decisions.mjs Line 693
486
498
  if (moduleKeys.length === 1 && moduleKeys[0] === moduleName) {
487
- return mod[moduleName]; // Auto-flatten single named export
499
+ return {
500
+ shouldFlatten: true,
501
+ flattenType: "object-auto-flatten"
502
+ };
488
503
  }
489
504
 
490
- // C20c: buildCategoryDecisions() multi-file - line 1731
505
+ // C21c: buildCategoryDecisions() multi-file - decisions.mjs Line 867
491
506
  else if (moduleKeys.length === 1 && moduleKeys[0] === apiPathKey) {
492
507
  moduleDecision.shouldFlatten = true;
493
508
  moduleDecision.flattenType = "single-named-export-match";
494
509
  }
495
510
 
496
- // C24: multidefault_getFlatteningDecision() - line 200
511
+ // C30: multidefault_getFlatteningDecision() - multidefault.mjs Line 231
497
512
  if (moduleKeys.length === 1 && moduleKeys[0] === apiPathKey) {
498
513
  return {
499
514
  shouldFlatten: true,
515
+ flattenToRoot: false,
500
516
  reason: "single named export matching filename"
501
517
  };
502
518
  }
@@ -521,7 +537,7 @@ node tests/debug-slothlet.mjs
521
537
  **Condition**: Various patterns for eliminating unnecessary nesting in single-file folders
522
538
  **Behavior**: Multiple sub-patterns for flattening single files based on different criteria
523
539
  **Source Code Conditions**: C10, C11a/C11b/C11c, C13, C15 (buildCategoryStructure single-file logic)
524
- **Git Commit**: `c2f081a321c738f86196fdfdb19b6a5a706022ef`
540
+ **Git Commit**: `a50531d1ba712f0c4efd9ab9b7cf8f62a0d379da`
525
541
 
526
542
  **Pattern A: Object Export Flattening** (C11a/C11b/C11c):
527
543
 
@@ -589,24 +605,39 @@ api.funcmod("test"); // → "Hello, test!" ✅ VERIFIED with api_tests/api_test
589
605
  **Technical Implementation**:
590
606
 
591
607
  ```javascript
592
- // C10: Single-file function folder match - line 984
608
+ // C10: Single-file function folder match - decisions.mjs Line 584
593
609
  if (moduleName === categoryName && typeof mod === "function" && currentDepth > 0) {
594
- return mod; // Return function directly
610
+ return {
611
+ shouldFlatten: true,
612
+ flattenType: "function-folder-match"
613
+ };
595
614
  }
596
615
 
597
- // C11a: Single named export match - line 1000
598
- if (moduleKeys.length === 1 && moduleKeys[0] === moduleName) {
599
- return mod[moduleName]; // Return export contents directly
616
+ // C12: Object auto-flatten - decisions.mjs Line 604-609
617
+ if (moduleName === categoryName && mod && typeof mod === "object" && currentDepth > 0) {
618
+ if (moduleKeys.length === 1 && moduleKeys[0] === moduleName) {
619
+ return {
620
+ shouldFlatten: true,
621
+ flattenType: "object-auto-flatten"
622
+ };
623
+ }
600
624
  }
601
625
 
602
- // C13: Function name matches folder - line 1039
626
+ // C15: Function name matches folder - decisions.mjs Line 663
603
627
  if (functionNameMatchesFolder && currentDepth > 0) {
604
- return mod; // Return function with preserved name
628
+ return {
629
+ shouldFlatten: true,
630
+ flattenType: "function-folder-match",
631
+ preferredName: mod.name
632
+ };
605
633
  }
606
634
 
607
- // C15: Default function export - line 1053
608
- if (typeof mod === "function" && mod.__slothletDefault === true && currentDepth > 0) {
609
- return mod; // Flatten default function
635
+ // C17: Default function export - decisions.mjs Line 680-682
636
+ if (typeof mod === "function" && (!mod.name || mod.name === "default" || mod.__slothletDefault === true) && currentDepth > 0) {
637
+ return {
638
+ shouldFlatten: true,
639
+ flattenType: "default-function"
640
+ };
610
641
  }
611
642
  ```
612
643
 
@@ -620,8 +651,8 @@ if (typeof mod === "function" && mod.__slothletDefault === true && currentDepth
620
651
 
621
652
  **Condition**: Original function name semantically matches sanitized filename but has different casing
622
653
  **Behavior**: Use original function name instead of sanitized version to preserve conventions (IP, JSON, HTTP, etc.)
623
- **Source Code Conditions**: C14, C18 (function name preference logic)
624
- **Git Commit**: `c2f081a321c738f86196fdfdb19b6a5a706022ef`
654
+ **Source Code Conditions**: [C16](API-RULES-CONDITIONS.md#c16-function-name-matches-filename-name-preference), [C19](API-RULES-CONDITIONS.md#c19-multi-file-function-with-preferred-name) (function name preference logic)
655
+ **Git Commit**: `a50531d1ba712f0c4efd9ab9b7cf8f62a0d379da`
625
656
 
626
657
  **Verified Examples**:
627
658
 
@@ -644,10 +675,19 @@ if (functionNameMatchesFilename) {
644
675
  return { [mod.name]: mod }; // Use original function name
645
676
  }
646
677
 
647
- // C18: buildCategoryDecisions() preferred export names - line 1709
678
+ // C16: Function name matches filename - decisions.mjs Line 671
679
+ if (functionNameMatchesFilename) {
680
+ return {
681
+ shouldFlatten: false,
682
+ preferredName: mod.name
683
+ };
684
+ }
685
+
686
+ // C19: Multi-file function with preferred name - decisions.mjs Line 844
648
687
  if (hasPreferredName) {
649
- moduleDecision.specialHandling = "preferred-export-names";
650
- moduleDecision.processedExports = modWithPreferredNames;
688
+ return {
689
+ specialHandling: "preferred-export-names"
690
+ };
651
691
  }
652
692
 
653
693
  // Function name preference logic checks:
@@ -676,8 +716,8 @@ node tests/debug-slothlet.mjs
676
716
 
677
717
  **Condition**: Single export with generic filename (singlefile, index, main, default) in subfolder
678
718
  **Behavior**: Promote export to parent level to eliminate meaningless intermediate namespace
679
- **Source Code Conditions**: C12, C12a (parent-level flattening logic)
680
- **Git Commit**: `c2f081a321c738f86196fdfdb19b6a5a706022ef`
719
+ **Source Code Conditions**: [C14](API-RULES-CONDITIONS.md#c14-parent-level-flattening-generic-filenames) (parent-level flattening logic)
720
+ **Git Commit**: `a50531d1ba712f0c4efd9ab9b7cf8f62a0d379da`
681
721
 
682
722
  **Verified Examples**:
683
723
 
@@ -695,14 +735,16 @@ api.advanced.nest4.beta("test"); // → "Hello, test!" ✅ VERIFIED with api_tes
695
735
  **Technical Implementation**:
696
736
 
697
737
  ```javascript
698
- // C12: Parent-level flattening detection - line 1018
738
+ // C14: Parent-level flattening detection - decisions.mjs Line 641
699
739
  if (moduleFiles.length === 1 && currentDepth > 0 && mod && typeof mod === "object" && !Array.isArray(mod)) {
700
740
  const isGenericFilename = ["singlefile", "index", "main", "default"].includes(fileName.toLowerCase());
701
741
 
702
- // C12a: Generic filename single export promotion - line 1026
742
+ // Line 649: Generic filename single export promotion
703
743
  if (moduleKeys.length === 1 && isGenericFilename) {
704
- const exportValue = mod[moduleKeys[0]];
705
- return { [moduleKeys[0]]: exportValue }; // Promote to parent level
744
+ return {
745
+ shouldFlatten: true,
746
+ flattenType: "parent-level-flatten"
747
+ };
706
748
  }
707
749
  }
708
750
  ```
@@ -770,7 +812,20 @@ node tests/debug-slothlet.mjs
770
812
 
771
813
  ## Source Code Locations
772
814
 
773
- _To be populated as rules are verified_
815
+ **Note**: The slothlet API generation logic has been refactored into a modular structure:
816
+
817
+ - **`src/lib/helpers/api_builder/decisions.mjs`** - Core decision logic (899 lines)
818
+ - `getFlatteningDecision()` [L87-189] - Controls flattening behavior
819
+ - `processModuleForAPI()` [L315-466] - Module processing logic
820
+ - `buildCategoryDecisions()` [L505-899] - Directory structure decisions
821
+
822
+ - **`src/lib/helpers/api_builder/construction.mjs`** - API assembly (555 lines)
823
+ - `buildCategoryStructure()` [L125-555] - Structural construction
824
+
825
+ - **`src/lib/helpers/multidefault.mjs`** - Multi-default handling (262 lines)
826
+ - `multidefault_getFlatteningDecision()` [L178-262] - Multi-default flattening logic
827
+
828
+ **For complete documentation** of all 32 conditional statements with exact line numbers, see [API-RULES-CONDITIONS.md](API-RULES-CONDITIONS.md).
774
829
 
775
830
  ## Test File Index
776
831
 
package/package.json CHANGED
@@ -1,9 +1,11 @@
1
1
  {
2
2
  "name": "@cldmv/slothlet",
3
- "version": "2.8.0",
3
+ "version": "2.10.0",
4
4
  "moduleVersions": {
5
5
  "lazy": "1.3.1",
6
- "eager": "1.3.1"
6
+ "eager": "1.3.1",
7
+ "async": "1.1.0",
8
+ "live": "1.1.0"
7
9
  },
8
10
  "description": "Slothlet: Modular API Loader for Node.js. Lazy mode dynamically loads API modules and submodules only when accessed, supporting both lazy and eager loading.",
9
11
  "main": "./index.cjs",
@@ -92,12 +94,12 @@
92
94
  "build:dist": "shx mkdir -p dist && shx cp -r src/* dist/ && shx rm -rf dist/**/*.backup",
93
95
  "build:types": "npx tsc -p .configs/tsconfig.dts.jsonc",
94
96
  "build:docs": "npm run build:docs:slothlet && npm run build:docs:api-tests",
95
- "build:docs:slothlet": "jsdoc2md -g grouped -m dl --no-cache --separators -c \".configs/jsdoc.config.json\" --helper \"docs/helpers.cjs\" --template \"docs/template.hbs\" \"src/{slothlet.mjs,lib/{modes,helpers,runtime}/**/*.mjs}\" > docs/API.md",
97
+ "build:docs:slothlet": "jsdoc2md -g grouped -m dl --no-cache --separators -c \".configs/jsdoc.config.json\" --helper \"docs/generated/helpers.cjs\" --template \"docs/generated/template.hbs\" \"src/{slothlet.mjs,lib/{modes,helpers,runtime}/**/*.mjs}\" > docs/generated/API.md",
96
98
  "build:docs:api-tests": "npm run build:docs:api-test && npm run build:docs:api-test-cjs && npm run build:docs:api-test-mixed",
97
- "build:docs:api-test": "shx mkdir -p docs/api_tests && jsdoc2md -g grouped -m dl --no-cache --separators -c \".configs/jsdoc.config.json\" --helper \"docs/helpers.cjs\" --template \"docs/template.hbs\" \"api_tests/api_test/**/*.mjs\" > docs/api_tests/api_test.md",
98
- "build:docs:api-test-cjs": "shx mkdir -p docs/api_tests && jsdoc2md -g grouped -m dl --no-cache --separators -c \".configs/jsdoc.config.json\" --helper \"docs/helpers.cjs\" --template \"docs/template.hbs\" \"api_tests/api_test_cjs/**/*.{mjs,cjs}\" > docs/api_tests/api_test_cjs.md",
99
- "build:docs:api-test-mixed": "shx mkdir -p docs/api_tests && jsdoc2md -g grouped -m dl --no-cache --separators -c \".configs/jsdoc.config.json\" --helper \"docs/helpers.cjs\" --template \"docs/template.hbs\" \"api_tests/api_test_mixed/**/*.{mjs,cjs}\" > docs/api_tests/api_test_mixed.md",
100
- "build:docs:tools": "shx mkdir -p docs/tools && jsdoc2md -g grouped -m dl --no-cache --separators -c \".configs/jsdoc.config.json\" --helper \"docs/helpers.cjs\" --template \"docs/template.hbs\" \"tools/**/*.mjs\" > docs/tools/build-tools.md",
99
+ "build:docs:api-test": "shx mkdir -p docs/generated/api_tests && jsdoc2md -g grouped -m dl --no-cache --separators -c \".configs/jsdoc.config.json\" --helper \"docs/generated/helpers.cjs\" --template \"docs/generated/template.hbs\" \"api_tests/api_test/**/*.mjs\" > docs/generated/api_tests/api_test.md",
100
+ "build:docs:api-test-cjs": "shx mkdir -p docs/generated/api_tests && jsdoc2md -g grouped -m dl --no-cache --separators -c \".configs/jsdoc.config.json\" --helper \"docs/generated/helpers.cjs\" --template \"docs/generated/template.hbs\" \"api_tests/api_test_cjs/**/*.{mjs,cjs}\" > docs/generated/api_tests/api_test_cjs.md",
101
+ "build:docs:api-test-mixed": "shx mkdir -p docs/generated/api_tests && jsdoc2md -g grouped -m dl --no-cache --separators -c \".configs/jsdoc.config.json\" --helper \"docs/generated/helpers.cjs\" --template \"docs/generated/template.hbs\" \"api_tests/api_test_mixed/**/*.{mjs,cjs}\" > docs/generated/api_tests/api_test_mixed.md",
102
+ "build:docs:tools": "shx mkdir -p docs/tools && jsdoc2md -g grouped -m dl --no-cache --separators -c \".configs/jsdoc.config.json\" --helper \"docs/generated/helpers.cjs\" --template \"docs/generated/template.hbs\" \"tools/**/*.mjs\" > docs/tools/build-tools.md",
101
103
  "build:exports": "node tools/build-exports.mjs",
102
104
  "build:prepend-license": "node tools/prepend-license.mjs dist",
103
105
  "prepublish-check": "npm run build && npm pack && node tools/prepublish-check.mjs"
@@ -188,8 +190,8 @@
188
190
  "index.cjs",
189
191
  "README.md",
190
192
  "LICENSE",
191
- "API-RULES.md",
192
- "API-RULES-CONDITIONS.md",
193
+ "docs/API-RULES.md",
194
+ "docs/API-RULES-CONDITIONS.md",
193
195
  "AGENT-USAGE.md",
194
196
  "types/dist/",
195
197
  "types/index.d.mts",
@@ -1 +1 @@
1
- {"version":3,"file":"als-eventemitter.d.mts","sourceRoot":"","sources":["../../../../dist/lib/helpers/als-eventemitter.mjs"],"names":[],"mappings":"AAkDA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,8EAiNC;AAED;;;;;;;;;;;;;;GAcG;AACH;;;;;;;;;;;;;;;GAeG;AACH,oDAyBC;AAED,mDAmCC;kCApViC,kBAAkB"}
1
+ {"version":3,"file":"als-eventemitter.d.mts","sourceRoot":"","sources":["../../../../dist/lib/helpers/als-eventemitter.mjs"],"names":[],"mappings":"AAiDA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,8EAiNC;AAED;;;;;;;;;;;;;;GAcG;AACH;;;;;;;;;;;;;;;GAeG;AACH,oDAyBC;AAED,mDAmCC;kCArVgD,kBAAkB"}
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Dynamically adds API modules from a new folder to the existing API at a specified path.
3
+ *
4
+ * @function addApiFromFolder
5
+ * @memberof module:@cldmv/slothlet.lib.helpers.api_builder.add_api
6
+ * @param {object} options - Configuration object
7
+ * @param {string} options.apiPath - Dot-notation path where modules will be added
8
+ * @param {string} options.folderPath - Path to folder containing modules to load
9
+ * @param {object} options.instance - Slothlet instance with api, boundapi, config, modes, etc.
10
+ * @param {object} [options.metadata={}] - Metadata to attach to all loaded functions
11
+ * @returns {Promise<void>}
12
+ * @throws {Error} If API not loaded, invalid parameters, folder does not exist, or merge conflicts
13
+ * @package
14
+ *
15
+ * @description
16
+ * This function enables runtime extension of the API by loading modules from a folder
17
+ * and merging them into a specified location in the API tree. It performs comprehensive
18
+ * validation, supports both relative and absolute paths, handles intermediate object
19
+ * creation, and respects the allowApiOverwrite configuration.
20
+ *
21
+ * The method performs the following steps:
22
+ * 1. Validates that the API is loaded and the folder exists
23
+ * 2. Resolves relative folder paths from the caller location
24
+ * 3. Loads modules from the specified folder using the current loading mode
25
+ * 4. Navigates to the specified API path, creating intermediate objects as needed
26
+ * 5. Merges the new modules into the target location
27
+ * 6. Updates all live bindings to reflect the changes
28
+ *
29
+ * @example
30
+ * // Internal usage
31
+ * import { addApiFromFolder } from "./add_api.mjs";
32
+ *
33
+ * // Add additional modules at runtime.plugins path
34
+ * await addApiFromFolder({
35
+ * apiPath: "runtime.plugins",
36
+ * folderPath: "./plugins",
37
+ * instance: slothletInstance
38
+ * });
39
+ *
40
+ * @example
41
+ * // Add modules to root level
42
+ * await addApiFromFolder({
43
+ * apiPath: "utilities",
44
+ * folderPath: "./utils",
45
+ * instance: slothletInstance
46
+ * });
47
+ *
48
+ * @example
49
+ * // Add deep nested modules
50
+ * await addApiFromFolder({
51
+ * apiPath: "services.external.stripe",
52
+ * folderPath: "./services/stripe",
53
+ * instance: slothletInstance
54
+ * });
55
+ *
56
+ * @example
57
+ * // Add modules with metadata
58
+ * await addApiFromFolder({
59
+ * apiPath: "plugins",
60
+ * folderPath: "./untrusted-plugins",
61
+ * instance: slothletInstance,
62
+ * metadata: {
63
+ * trusted: false,
64
+ * permissions: ["read"],
65
+ * version: "1.0.0",
66
+ * author: "external"
67
+ * }
68
+ * });
69
+ */
70
+ export function addApiFromFolder({ apiPath, folderPath, instance, metadata }: {
71
+ apiPath: string;
72
+ folderPath: string;
73
+ instance: object;
74
+ metadata?: object;
75
+ }): Promise<void>;
76
+ //# sourceMappingURL=add_api.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"add_api.d.mts","sourceRoot":"","sources":["../../../../../dist/lib/helpers/api_builder/add_api.mjs"],"names":[],"mappings":"AAkDA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoEG;AACH,8EA/DG;IAAwB,OAAO,EAAvB,MAAM;IACU,UAAU,EAA1B,MAAM;IACU,QAAQ,EAAxB,MAAM;IACW,QAAQ,GAAzB,MAAM;CACd,GAAU,OAAO,CAAC,IAAI,CAAC,CAoUzB"}