@cldmv/slothlet 3.9.2 → 3.11.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 (181) hide show
  1. package/README.md +21 -21
  2. package/REFERENCE.md +19 -19
  3. package/dist/lib/builders/api_builder.mjs +1 -1
  4. package/dist/lib/builders/builder.mjs +1 -1
  5. package/dist/lib/builders/modes-processor.mjs +1 -1
  6. package/dist/lib/handlers/api-cache-manager.mjs +1 -1
  7. package/dist/lib/handlers/api-manager.mjs +1 -1
  8. package/dist/lib/handlers/hook-manager.mjs +1 -1
  9. package/dist/lib/handlers/permission-manager.mjs +1 -1
  10. package/dist/lib/handlers/unified-wrapper.mjs +1 -1
  11. package/dist/lib/helpers/config.mjs +1 -1
  12. package/dist/lib/helpers/generate-manifest.mjs +1 -1
  13. package/dist/lib/helpers/module-discovery.mjs +1 -1
  14. package/dist/lib/helpers/module-manifest-validator.mjs +1 -1
  15. package/dist/lib/helpers/platform.mjs +1 -1
  16. package/dist/lib/i18n/languages/en-us.json +92 -64
  17. package/dist/lib/i18n/translations.mjs +1 -1
  18. package/dist/lib/modes/eager.mjs +1 -1
  19. package/dist/lib/modes/lazy.mjs +1 -1
  20. package/dist/lib/processors/loader.mjs +1 -1
  21. package/dist/slothlet.mjs +1 -1
  22. package/package.json +64 -34
  23. package/types/stub/devcheck.d.mts +3 -0
  24. package/types/stub/index.d.mts +4 -0
  25. package/types/stub/lib/builders/api-assignment.d.mts +3 -0
  26. package/types/stub/lib/builders/api_builder.d.mts +3 -0
  27. package/types/stub/lib/builders/builder.d.mts +3 -0
  28. package/types/stub/lib/builders/modes-processor.d.mts +3 -0
  29. package/types/stub/lib/errors.d.mts +3 -0
  30. package/types/stub/lib/factories/component-base.d.mts +3 -0
  31. package/types/stub/lib/factories/context.d.mts +3 -0
  32. package/types/stub/lib/handlers/api-cache-manager.d.mts +3 -0
  33. package/types/stub/lib/handlers/api-manager.d.mts +3 -0
  34. package/types/stub/lib/handlers/context-async.d.mts +3 -0
  35. package/types/stub/lib/handlers/context-live.d.mts +3 -0
  36. package/types/stub/lib/handlers/hook-manager.d.mts +3 -0
  37. package/types/stub/lib/handlers/lifecycle-token.d.mts +3 -0
  38. package/types/stub/lib/handlers/lifecycle.d.mts +3 -0
  39. package/types/stub/lib/handlers/materialize-manager.d.mts +3 -0
  40. package/types/stub/lib/handlers/metadata.d.mts +3 -0
  41. package/types/stub/lib/handlers/module-manager.d.mts +3 -0
  42. package/types/stub/lib/handlers/ownership.d.mts +3 -0
  43. package/types/stub/lib/handlers/permission-manager.d.mts +3 -0
  44. package/types/stub/lib/handlers/unified-wrapper.d.mts +3 -0
  45. package/types/stub/lib/handlers/version-manager.d.mts +3 -0
  46. package/types/stub/lib/helpers/class-instance-wrapper.d.mts +3 -0
  47. package/types/stub/lib/helpers/config.d.mts +3 -0
  48. package/types/stub/lib/helpers/eventemitter-context.d.mts +3 -0
  49. package/types/stub/lib/helpers/generate-manifest.d.mts +3 -0
  50. package/types/stub/lib/helpers/hint-detector.d.mts +3 -0
  51. package/types/stub/lib/helpers/manifest-resolver.d.mts +3 -0
  52. package/types/stub/lib/helpers/modes-utils.d.mts +3 -0
  53. package/types/stub/lib/helpers/module-discovery.d.mts +3 -0
  54. package/types/stub/lib/helpers/module-manifest-validator.d.mts +3 -0
  55. package/types/stub/lib/helpers/module-sort.d.mts +3 -0
  56. package/types/stub/lib/helpers/pattern-matcher.d.mts +3 -0
  57. package/types/stub/lib/helpers/platform.d.mts +3 -0
  58. package/types/stub/lib/helpers/resolve-from-caller.d.mts +3 -0
  59. package/types/stub/lib/helpers/sanitize.d.mts +3 -0
  60. package/types/stub/lib/helpers/utilities.d.mts +3 -0
  61. package/types/stub/lib/i18n/translations.d.mts +3 -0
  62. package/types/stub/lib/modes/eager.d.mts +3 -0
  63. package/types/stub/lib/modes/lazy.d.mts +3 -0
  64. package/types/stub/lib/processors/flatten.d.mts +3 -0
  65. package/types/stub/lib/processors/loader.d.mts +3 -0
  66. package/types/stub/lib/processors/type-generator.d.mts +3 -0
  67. package/types/stub/lib/processors/typescript.d.mts +3 -0
  68. package/types/stub/lib/runtime/runtime-asynclocalstorage.d.mts +3 -0
  69. package/types/stub/lib/runtime/runtime-livebindings.d.mts +3 -0
  70. package/types/stub/lib/runtime/runtime.d.mts +3 -0
  71. package/types/stub/lib/typegen/typegen.d.mts +3 -0
  72. package/types/stub/slothlet.d.mts +4 -0
  73. package/dist/lib/i18n/languages/de-de.json +0 -444
  74. package/dist/lib/i18n/languages/en-gb.json +0 -444
  75. package/dist/lib/i18n/languages/es-es.json +0 -444
  76. package/dist/lib/i18n/languages/es-mx.json +0 -444
  77. package/dist/lib/i18n/languages/fr-fr.json +0 -444
  78. package/dist/lib/i18n/languages/hi-in.json +0 -444
  79. package/dist/lib/i18n/languages/ja-jp.json +0 -444
  80. package/dist/lib/i18n/languages/ko-kr.json +0 -444
  81. package/dist/lib/i18n/languages/pt-br.json +0 -444
  82. package/dist/lib/i18n/languages/ru-ru.json +0 -444
  83. package/dist/lib/i18n/languages/zh-cn.json +0 -444
  84. package/types/dist/lib/builders/api-assignment.d.mts +0 -8
  85. package/types/dist/lib/builders/api-assignment.d.mts.map +0 -1
  86. package/types/dist/lib/builders/api_builder.d.mts +0 -12
  87. package/types/dist/lib/builders/api_builder.d.mts.map +0 -1
  88. package/types/dist/lib/builders/builder.d.mts +0 -6
  89. package/types/dist/lib/builders/builder.d.mts.map +0 -1
  90. package/types/dist/lib/builders/modes-processor.d.mts +0 -8
  91. package/types/dist/lib/builders/modes-processor.d.mts.map +0 -1
  92. package/types/dist/lib/errors.d.mts +0 -28
  93. package/types/dist/lib/errors.d.mts.map +0 -1
  94. package/types/dist/lib/factories/component-base.d.mts +0 -12
  95. package/types/dist/lib/factories/component-base.d.mts.map +0 -1
  96. package/types/dist/lib/factories/context.d.mts +0 -8
  97. package/types/dist/lib/factories/context.d.mts.map +0 -1
  98. package/types/dist/lib/handlers/api-cache-manager.d.mts +0 -25
  99. package/types/dist/lib/handlers/api-cache-manager.d.mts.map +0 -1
  100. package/types/dist/lib/handlers/api-manager.d.mts +0 -47
  101. package/types/dist/lib/handlers/api-manager.d.mts.map +0 -1
  102. package/types/dist/lib/handlers/context-async.d.mts +0 -28
  103. package/types/dist/lib/handlers/context-async.d.mts.map +0 -1
  104. package/types/dist/lib/handlers/context-live.d.mts +0 -28
  105. package/types/dist/lib/handlers/context-live.d.mts.map +0 -1
  106. package/types/dist/lib/handlers/hook-manager.d.mts +0 -65
  107. package/types/dist/lib/handlers/hook-manager.d.mts.map +0 -1
  108. package/types/dist/lib/handlers/lifecycle-token.d.mts +0 -4
  109. package/types/dist/lib/handlers/lifecycle-token.d.mts.map +0 -1
  110. package/types/dist/lib/handlers/lifecycle.d.mts +0 -13
  111. package/types/dist/lib/handlers/lifecycle.d.mts.map +0 -1
  112. package/types/dist/lib/handlers/materialize-manager.d.mts +0 -13
  113. package/types/dist/lib/handlers/materialize-manager.d.mts.map +0 -1
  114. package/types/dist/lib/handlers/metadata.d.mts +0 -26
  115. package/types/dist/lib/handlers/metadata.d.mts.map +0 -1
  116. package/types/dist/lib/handlers/module-manager.d.mts +0 -29
  117. package/types/dist/lib/handlers/module-manager.d.mts.map +0 -1
  118. package/types/dist/lib/handlers/ownership.d.mts +0 -57
  119. package/types/dist/lib/handlers/ownership.d.mts.map +0 -1
  120. package/types/dist/lib/handlers/permission-manager.d.mts +0 -54
  121. package/types/dist/lib/handlers/permission-manager.d.mts.map +0 -1
  122. package/types/dist/lib/handlers/unified-wrapper.d.mts +0 -37
  123. package/types/dist/lib/handlers/unified-wrapper.d.mts.map +0 -1
  124. package/types/dist/lib/handlers/version-manager.d.mts +0 -37
  125. package/types/dist/lib/handlers/version-manager.d.mts.map +0 -1
  126. package/types/dist/lib/helpers/class-instance-wrapper.d.mts +0 -4
  127. package/types/dist/lib/helpers/class-instance-wrapper.d.mts.map +0 -1
  128. package/types/dist/lib/helpers/config.d.mts +0 -150
  129. package/types/dist/lib/helpers/config.d.mts.map +0 -1
  130. package/types/dist/lib/helpers/eventemitter-context.d.mts +0 -5
  131. package/types/dist/lib/helpers/eventemitter-context.d.mts.map +0 -1
  132. package/types/dist/lib/helpers/generate-manifest.d.mts +0 -11
  133. package/types/dist/lib/helpers/generate-manifest.d.mts.map +0 -1
  134. package/types/dist/lib/helpers/hint-detector.d.mts +0 -7
  135. package/types/dist/lib/helpers/hint-detector.d.mts.map +0 -1
  136. package/types/dist/lib/helpers/manifest-resolver.d.mts +0 -2
  137. package/types/dist/lib/helpers/manifest-resolver.d.mts.map +0 -1
  138. package/types/dist/lib/helpers/modes-utils.d.mts +0 -8
  139. package/types/dist/lib/helpers/modes-utils.d.mts.map +0 -1
  140. package/types/dist/lib/helpers/module-discovery.d.mts +0 -8
  141. package/types/dist/lib/helpers/module-discovery.d.mts.map +0 -1
  142. package/types/dist/lib/helpers/module-manifest-validator.d.mts +0 -14
  143. package/types/dist/lib/helpers/module-manifest-validator.d.mts.map +0 -1
  144. package/types/dist/lib/helpers/module-sort.d.mts +0 -2
  145. package/types/dist/lib/helpers/module-sort.d.mts.map +0 -1
  146. package/types/dist/lib/helpers/pattern-matcher.d.mts +0 -4
  147. package/types/dist/lib/helpers/pattern-matcher.d.mts.map +0 -1
  148. package/types/dist/lib/helpers/platform.d.mts +0 -12
  149. package/types/dist/lib/helpers/platform.d.mts.map +0 -1
  150. package/types/dist/lib/helpers/resolve-from-caller.d.mts +0 -9
  151. package/types/dist/lib/helpers/resolve-from-caller.d.mts.map +0 -1
  152. package/types/dist/lib/helpers/sanitize.d.mts +0 -10
  153. package/types/dist/lib/helpers/sanitize.d.mts.map +0 -1
  154. package/types/dist/lib/helpers/utilities.d.mts +0 -9
  155. package/types/dist/lib/helpers/utilities.d.mts.map +0 -1
  156. package/types/dist/lib/i18n/translations.d.mts +0 -7
  157. package/types/dist/lib/i18n/translations.d.mts.map +0 -1
  158. package/types/dist/lib/modes/eager.d.mts +0 -14
  159. package/types/dist/lib/modes/eager.d.mts.map +0 -1
  160. package/types/dist/lib/modes/lazy.d.mts +0 -16
  161. package/types/dist/lib/modes/lazy.d.mts.map +0 -1
  162. package/types/dist/lib/processors/flatten.d.mts +0 -63
  163. package/types/dist/lib/processors/flatten.d.mts.map +0 -1
  164. package/types/dist/lib/processors/loader.d.mts +0 -12
  165. package/types/dist/lib/processors/loader.d.mts.map +0 -1
  166. package/types/dist/lib/processors/type-generator.d.mts +0 -5
  167. package/types/dist/lib/processors/type-generator.d.mts.map +0 -1
  168. package/types/dist/lib/processors/typescript.d.mts +0 -18
  169. package/types/dist/lib/processors/typescript.d.mts.map +0 -1
  170. package/types/dist/lib/runtime/runtime-asynclocalstorage.d.mts +0 -4
  171. package/types/dist/lib/runtime/runtime-asynclocalstorage.d.mts.map +0 -1
  172. package/types/dist/lib/runtime/runtime-livebindings.d.mts +0 -3
  173. package/types/dist/lib/runtime/runtime-livebindings.d.mts.map +0 -1
  174. package/types/dist/lib/runtime/runtime.d.mts +0 -4
  175. package/types/dist/lib/runtime/runtime.d.mts.map +0 -1
  176. package/types/dist/lib/typegen/typegen.d.mts +0 -5
  177. package/types/dist/lib/typegen/typegen.d.mts.map +0 -1
  178. package/types/dist/slothlet.d.mts +0 -4
  179. package/types/dist/slothlet.d.mts.map +0 -1
  180. package/types/index.d.mts +0 -18
  181. package/types/index.d.mts.map +0 -1
package/README.md CHANGED
@@ -43,19 +43,19 @@ Every feature has been hardened with a comprehensive test suite - over **5,300 t
43
43
 
44
44
  ## ✨ What's New
45
45
 
46
- ### Latest: v3.9.2 (May 2026)
46
+ ### Latest: v3.11.0 (June 2026)
47
47
 
48
- - **Browser mode is now actually loadable** — `generateBrowserAssets(apiDir)` returns both the API manifest **and** an importmap for slothlet's own modules, generated from its real module graph and rebased onto a configurable `slothletBase` (default `/node_modules/@cldmv/slothlet/`). Browser consumers no longer hand-roll module resolution; slothlet is verified loading end-to-end in a real headless browser (#123). See the new [Browser / Worker Mode](./docs/BROWSER.md) guide.
49
- - **Critical runtime + hook fixes** — the async runtime no longer double-wraps chainable class instances, which caused a `2^N` blow-up on fluent APIs like query builders (#124); the global `hook.pattern` filter is now actually enforced, and the long-broken string/boolean `hook` config forms now enable hooks (#125).
50
- - **`npm run docs:build` fixed** — a jsdoc plugin lets the doc generator parse the codebase's TypeScript-style JSDoc types (#121).
51
- - [View full v3.9.2 Changelog](./docs/changelog/v3/v3.9.2.md)
48
+ - **Satellite packages** — slothlet is now a lean core plus two optional satellites. Non-base locales load from the optional `@cldmv/slothlet-i18n` pack (auto-detected at runtime via `import.meta.resolve`), so core ships only the `en-us` base locale. The full TypeScript declarations move to the optional `@cldmv/slothlet-types` package and core ships thin re-export stubs. Both satellites are optional peer dependencies pinned to `^3.11.0`, carved from this single repo by a CI build step (#155).
49
+ - **Loader `hidden` option; `.`/`__` hidden by default** — dot- and double-underscore-prefixed names are now hidden by default for folders as well as files. The unreleased `ignore` option is renamed to `hidden` and matches files and folders via globs evaluated gitignore-style (ordered, last match wins, `!` un-hides). A deprecated `scanHiddenFolders` escape hatch (removed in v4) restores scanning of dot/double-underscore folders (#155).
50
+ - **Browser-mode v8 coverage** — coverage is now collected in a real Chromium browser (vitest browser mode) and merged with node coverage via a location-based merge; the `analyze` audit now catches unbalanced `v8 ignore start/stop` ranges, which had silently truncated the coverage maps of the three largest source files (#162).
51
+ - [View full v3.11.0 Changelog](./docs/changelog/v3/v3.11.0.md)
52
52
 
53
53
  ### Recent Releases
54
54
 
55
+ - **v3.10.0** (June 2026) — Synthetic / in-memory leaves for `api.slothlet.api.add()` (inline function or export map, no temp file); hooks integrated with the permission system (gated registration/firing, owner-pinned, `pattern:type` selectors); browser importmap built from the full public export surface ([Changelog](./docs/changelog/v3/v3.10.0.md))
56
+ - **v3.9.2** (May 2026) — Browser mode actually loadable: `generateBrowserAssets()` returns the API manifest **and** slothlet's own importmap; fixes an async double-wrap blow-up on chainable instances (#124), the dead global hook pattern filter (#125), and `npm run docs:build` (#121) ([Changelog](./docs/changelog/v3/v3.9.2.md))
55
57
  - **v3.9.1** (May 2026) — Browser-mode hardening: consolidated `node:*` gating fixes a live-binding `self`/`context` crash (#123), idempotent full `reload()` (#91), correct eager `api.remove`; adds `setLanguageAsync()` and raises Node to ≥ 22 ([Changelog](./docs/changelog/v3/v3.9.1.md))
56
58
  - **v3.9.0** (May 2026) — Browser / worker mode: manifest-based api loading with no filesystem access; `generateManifest()` build-time helper; `platform` vs `env` split; `dir` → `base` migration ([Changelog](./docs/changelog/v3/v3.9.0.md))
57
- - **v3.8.0** (May 2026) — Module discovery + mount pipeline: `api.slothlet.api.modules.*` composes subsystems shipped as separate npm packages into the api tree at runtime; multi-version routing; five new lifecycle events ([Changelog](./docs/changelog/v3/v3.8.0.md))
58
- - **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))
59
59
 
60
60
  📚 **For complete version history and detailed release notes, see [docs/changelog/](./docs/changelog/) folder.**
61
61
 
@@ -113,9 +113,9 @@ Path-based access control for inter-module API calls **and** data-value reads (v
113
113
 
114
114
  ### 🌍 **Full Internationalization** _(new in v3)_
115
115
 
116
- All error messages and debug output are translated. Supported languages: English · Spanish · French · German · Portuguese · Italian · Japanese · Chinese (Simplified) · Korean
116
+ All error messages and debug output are translated. Supported languages: English (US/UK) · Spanish (Spain/Mexico) · French · German · Portuguese · Hindi · Japanese · Korean · Russian · Chinese (Simplified)
117
117
 
118
- Configure via `i18n: { language: "es" }` in your slothlet config. See **[docs/I18N.md](./docs/I18N.md)**.
118
+ Only US English (`en-us`) ships built in; every other locale — including UK English (`en-gb`) — comes from the optional **`@cldmv/slothlet-i18n`** package installed alongside slothlet (auto-detected, nothing to import or configure). Configure the language via `i18n: { language: "es-mx" }` in your slothlet config. See **[docs/I18N.md](./docs/I18N.md)**.
119
119
 
120
120
  ### 🔄 **Context Propagation**
121
121
 
@@ -169,7 +169,7 @@ Run slothlet in the browser, web workers, and Electron renderers — anywhere th
169
169
 
170
170
  ### Requirements
171
171
 
172
- - **Node.js v20.19.0 or higher**
172
+ - **Node.js v22.0.0 or higher**
173
173
 
174
174
  ### Install
175
175
 
@@ -221,17 +221,17 @@ The most-used options are summarized below. The complete reference — every opt
221
221
  | `permissions` | `object` | `undefined` | Path-based access control; see **[PERMISSIONS.md](./docs/PERMISSIONS.md)** |
222
222
  | `i18n` | `object` | `{}` | Language for translated error/debug messages — see **[I18N.md](./docs/I18N.md)** |
223
223
 
224
- 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)**.
224
+ Also configurable: `apiDepth`, `hidden` (globs hiding files/folders from the API), `debug`, `reference`, `sanitize`, `backgroundMaterialize`, `api.collision`, `api.mutations`, `versionDispatcher`, `typescript`, plus diagnostics and lifecycle internals. All documented in **[CONFIGURATION.md](./docs/CONFIGURATION.md)**.
225
225
 
226
226
  ---
227
227
 
228
228
  ## 🔀 Loading Modes
229
229
 
230
- | Mode | Startup | Function calls | Best for |
231
- | -------------------------------------- | -------------- | --------------------------------------------- | --------------------------------------------------- |
232
- | **Eager** (default) | Loads upfront | Sync stays sync, async stays async | Production, predictable performance |
233
- | **Lazy** | 2.2× faster | All calls awaited; materialized on first use | Large APIs, startup-sensitive apps |
234
- | **Lazy + `backgroundMaterialize`** | 2.2× faster | Pre-warmed by background loader | Best of both — lazy startup, eager runtime |
230
+ | Mode | Startup | Function calls | Best for |
231
+ | ---------------------------------- | ------------- | -------------------------------------------- | ------------------------------------------ |
232
+ | **Eager** (default) | Loads upfront | Sync stays sync, async stays async | Production, predictable performance |
233
+ | **Lazy** | 2.2× faster | All calls awaited; materialized on first use | Large APIs, startup-sensitive apps |
234
+ | **Lazy + `backgroundMaterialize`** | 2.2× faster | Pre-warmed by background loader | Best of both — lazy startup, eager runtime |
235
235
 
236
236
  ```javascript
237
237
  // Lazy + background materialization
@@ -251,10 +251,10 @@ Four hook types (`before`, `after`, `always`, `error`) with three-phase subset o
251
251
  ```javascript
252
252
  const api = await slothlet({ dir: "./api", hook: true });
253
253
 
254
- api.slothlet.hook.on("before:math.add", ({ args }) => [args[0] * 2, args[1] * 2], { id: "double" });
255
- api.slothlet.hook.on("after:math.*", ({ result }) => result * 10, { id: "scale" });
256
- api.slothlet.hook.on("always:**", ({ path, hasError }) => console.log(path, hasError));
257
- api.slothlet.hook.on("error:**", ({ path, error, source }) => console.error(path, source.type, error));
254
+ api.slothlet.hook.on("math.add:before", ({ args }) => [args[0] * 2, args[1] * 2], { id: "double" });
255
+ api.slothlet.hook.on("math.*:after", ({ result }) => result * 10, { id: "scale" });
256
+ api.slothlet.hook.on("**:always", ({ path, hasError }) => console.log(path, hasError));
257
+ api.slothlet.hook.on("**:error", ({ path, error, source }) => console.error(path, source.type, error));
258
258
 
259
259
  const out = await api.math.add(2, 3); // hooks fire automatically
260
260
  ```
@@ -292,7 +292,7 @@ await api.slothlet.api.remove("oldModule"); // remove
292
292
  await api.slothlet.api.reload("database.*"); // hot-reload
293
293
  ```
294
294
 
295
- 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).
295
+ Collision modes (`merge` / `merge-replace` / `replace` / `skip` / `warn` / `error`) — 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).
296
296
 
297
297
  🔁 **Full reference: [docs/RELOAD.md](./docs/RELOAD.md)** · 🏷️ **Metadata system: [docs/METADATA.md](./docs/METADATA.md)**
298
298
 
package/REFERENCE.md CHANGED
@@ -4,22 +4,22 @@ Full documentation lives in the GitHub repository.
4
4
 
5
5
  ## Documentation
6
6
 
7
- | Topic | Link |
8
- |---|---|
9
- | README / overview | [README.md](https://github.com/CLDMV/slothlet/blob/master/README.md) |
10
- | All docs | [docs/](https://github.com/CLDMV/slothlet/tree/master/docs) |
11
- | Configuration | [docs/CONFIGURATION.md](https://github.com/CLDMV/slothlet/blob/master/docs/CONFIGURATION.md) |
12
- | API transformation rules | [docs/API-RULES.md](https://github.com/CLDMV/slothlet/blob/master/docs/API-RULES.md) |
13
- | Hooks | [docs/HOOKS.md](https://github.com/CLDMV/slothlet/blob/master/docs/HOOKS.md) |
14
- | Context propagation | [docs/CONTEXT-PROPAGATION.md](https://github.com/CLDMV/slothlet/blob/master/docs/CONTEXT-PROPAGATION.md) |
15
- | Metadata | [docs/METADATA.md](https://github.com/CLDMV/slothlet/blob/master/docs/METADATA.md) |
16
- | Module discovery & mount | [docs/MODULE-DISCOVERY.md](https://github.com/CLDMV/slothlet/blob/master/docs/MODULE-DISCOVERY.md) |
17
- | Module manifest schema | [schemas/slothlet.module.schema.json](https://github.com/CLDMV/slothlet/blob/master/schemas/slothlet.module.schema.json) |
18
- | Permissions | [docs/PERMISSIONS.md](https://github.com/CLDMV/slothlet/blob/master/docs/PERMISSIONS.md) |
19
- | API versioning | [docs/VERSIONING.md](https://github.com/CLDMV/slothlet/blob/master/docs/VERSIONING.md) |
20
- | TypeScript | [docs/TYPESCRIPT.md](https://github.com/CLDMV/slothlet/blob/master/docs/TYPESCRIPT.md) |
21
- | Lifecycle | [docs/LIFECYCLE.md](https://github.com/CLDMV/slothlet/blob/master/docs/LIFECYCLE.md) |
22
- | Hot reload | [docs/RELOAD.md](https://github.com/CLDMV/slothlet/blob/master/docs/RELOAD.md) |
23
- | Performance | [docs/PERFORMANCE.md](https://github.com/CLDMV/slothlet/blob/master/docs/PERFORMANCE.md) |
24
- | Changelog | [docs/changelog/](https://github.com/CLDMV/slothlet/tree/master/docs/changelog) |
25
- | Agent/AI usage guide | [AGENT-USAGE.md](https://github.com/CLDMV/slothlet/blob/master/AGENT-USAGE.md) |
7
+ | Topic | Link |
8
+ | ------------------------ | ------------------------------------------------------------------------------------------------------------------------ |
9
+ | README / overview | [README.md](https://github.com/CLDMV/slothlet/blob/master/README.md) |
10
+ | All docs | [docs/](https://github.com/CLDMV/slothlet/tree/master/docs) |
11
+ | Configuration | [docs/CONFIGURATION.md](https://github.com/CLDMV/slothlet/blob/master/docs/CONFIGURATION.md) |
12
+ | API transformation rules | [docs/API-RULES.md](https://github.com/CLDMV/slothlet/blob/master/docs/API-RULES.md) |
13
+ | Hooks | [docs/HOOKS.md](https://github.com/CLDMV/slothlet/blob/master/docs/HOOKS.md) |
14
+ | Context propagation | [docs/CONTEXT-PROPAGATION.md](https://github.com/CLDMV/slothlet/blob/master/docs/CONTEXT-PROPAGATION.md) |
15
+ | Metadata | [docs/METADATA.md](https://github.com/CLDMV/slothlet/blob/master/docs/METADATA.md) |
16
+ | Module discovery & mount | [docs/MODULE-DISCOVERY.md](https://github.com/CLDMV/slothlet/blob/master/docs/MODULE-DISCOVERY.md) |
17
+ | Module manifest schema | [schemas/slothlet.module.schema.json](https://github.com/CLDMV/slothlet/blob/master/schemas/slothlet.module.schema.json) |
18
+ | Permissions | [docs/PERMISSIONS.md](https://github.com/CLDMV/slothlet/blob/master/docs/PERMISSIONS.md) |
19
+ | API versioning | [docs/VERSIONING.md](https://github.com/CLDMV/slothlet/blob/master/docs/VERSIONING.md) |
20
+ | TypeScript | [docs/TYPESCRIPT.md](https://github.com/CLDMV/slothlet/blob/master/docs/TYPESCRIPT.md) |
21
+ | Lifecycle | [docs/LIFECYCLE.md](https://github.com/CLDMV/slothlet/blob/master/docs/LIFECYCLE.md) |
22
+ | Hot reload | [docs/RELOAD.md](https://github.com/CLDMV/slothlet/blob/master/docs/RELOAD.md) |
23
+ | Performance | [docs/PERFORMANCE.md](https://github.com/CLDMV/slothlet/blob/master/docs/PERFORMANCE.md) |
24
+ | Changelog | [docs/changelog/](https://github.com/CLDMV/slothlet/tree/master/docs/changelog) |
25
+ | Agent/AI usage guide | [AGENT-USAGE.md](https://github.com/CLDMV/slothlet/blob/master/AGENT-USAGE.md) |
@@ -14,4 +14,4 @@
14
14
  limitations under the License.
15
15
  */
16
16
 
17
- import{isNode,AsyncResource,loadJson}from"@cldmv/slothlet/helpers/platform";import{ComponentBase}from"@cldmv/slothlet/factories/component-base";import{TYPE_STATES}from"@cldmv/slothlet/handlers/unified-wrapper";import{getLanguage,initI18n,setLanguage,setLanguageAsync,t,translate}from"@cldmv/slothlet/i18n";function _resolvePathOrModuleId(slothlet,pathOrModuleId){const history=slothlet.handlers?.apiManager?.state?.addHistory;if(history){let match=null;for(let i=history.length-1;i>=0;i--){const entry=history[i];if(entry?.moduleID===pathOrModuleId){match=entry;break}}if(match)return match.apiPath}return pathOrModuleId}function makeCopyOnWriteSelf(parentSelf){const overlay=new Map;const childViews=new Map;return new Proxy({},{get(_t,prop){if(overlay.has(prop))return overlay.get(prop);const real=parentSelf[prop];if(real!==null&&typeof real==="object"){let view=childViews.get(prop);if(view===void 0){view=makeCopyOnWriteSelf(real);childViews.set(prop,view)}return view}return real},set(_t,prop,value){overlay.set(prop,value);childViews.delete(prop);return true},has(_t,prop){return overlay.has(prop)||prop in parentSelf},deleteProperty(_t,prop){overlay.delete(prop);childViews.delete(prop);return true},ownKeys(){const keys=new Set(Reflect.ownKeys(parentSelf));for(const k of overlay.keys())keys.add(k);return[...keys]},getOwnPropertyDescriptor(_t,prop){if(overlay.has(prop)){return{value:overlay.get(prop),writable:true,enumerable:true,configurable:true}}const desc=Reflect.getOwnPropertyDescriptor(parentSelf,prop);return desc?{...desc,configurable:true}:void 0}})}class ApiBuilder extends ComponentBase{static slothletProperty="apiBuilder";constructor(slothlet){super(slothlet)}async buildFinalAPI(userApi){this.slothlet.debug("api",{key:"DEBUG_MODE_BUILD_FINAL_API_CALLED",diagnostics:this.____config.diagnostics,userApiKeys:Object.keys(userApi)});if(this.slothlet._ownBuiltins){for(const[key,ref]of Object.entries(this.slothlet._ownBuiltins)){if(ref&&Object.prototype.hasOwnProperty.call(userApi,key)&&userApi[key]===ref){try{delete userApi[key]}catch(_){}}}}this.slothlet.userHooks={shutdown:typeof userApi.shutdown==="function"?userApi.shutdown:null,destroy:typeof userApi.destroy==="function"?userApi.destroy:null};if(userApi.slothlet){new this.SlothletWarning("WARNING_RESERVED_PROPERTY_CONFLICT",{properties:"slothlet"})}const slothletNamespace=await this.createSlothletNamespace(userApi);this.slothlet.debug("api",{key:"DEBUG_MODE_SLOTHLET_NAMESPACE_CREATED",namespaceKeys:Object.keys(slothletNamespace),hasDiag:!!slothletNamespace.diag});const shutdownFn=this.createShutdownFunction();this.attachBuiltins(userApi,{slothlet:slothletNamespace,shutdown:shutdownFn,destroy:null});this.slothlet.debug("api",{key:"DEBUG_MODE_BUILT_INS_ATTACHED",userApiKeys:Object.keys(userApi),hasSlothlet:!!userApi.slothlet,hasDiag:!!userApi.slothlet?.diag});const destroyWithApi=this.createDestroyFunction(userApi);Object.defineProperty(userApi,"destroy",{value:destroyWithApi,enumerable:true,writable:false,configurable:true});this.slothlet._ownBuiltins={shutdown:shutdownFn,slothlet:slothletNamespace,destroy:destroyWithApi};return userApi}async createSlothletNamespace(userApi){const slothlet=this.slothlet;const config=this.____config;const enforceInternalPermission=targetPath=>{const ctx=slothlet.contextManager?.tryGetContext?.();const callerWrapper=ctx?.currentWrapper;if(!callerWrapper)return;const permissionManager=slothlet.handlers?.permissionManager;if(!permissionManager?.enforceAccess){throw new slothlet.SlothletError("PERMISSION_MANAGER_NOT_AVAILABLE",{validationError:true})}const callerPath=callerWrapper.____slothletInternal?.apiPath??"";const callerFilePath=callerWrapper.____slothletInternal?.filePath??null;const runtimeContext=ctx?.context??null;if(!permissionManager.enforceAccess(callerPath,targetPath,callerFilePath,null,runtimeContext)){throw new slothlet.SlothletError("PERMISSION_DENIED",{caller:callerPath,target:targetPath})}};const canTraverseInternalNamespace=targetPath=>{const ctx=slothlet.contextManager?.tryGetContext?.();const callerWrapper=ctx?.currentWrapper;if(!callerWrapper)return false;const permissionManager=slothlet.handlers?.permissionManager;if(!permissionManager?.getRulesForCaller||!permissionManager?.checkAccess){return false}const callerPath=callerWrapper.____slothletInternal?.apiPath??"";const callerFilePath=callerWrapper.____slothletInternal?.filePath??null;const runtimeContext=ctx?.context??null;const callerRules=permissionManager.getRulesForCaller(callerPath);const conditionMatches=condition=>typeof permissionManager.matchesCondition==="function"?permissionManager.matchesCondition(condition,runtimeContext):false;const prefix=`${targetPath}.`;for(const rule of callerRules){if(!rule||rule.effect!=="allow"||typeof rule.target!=="string")continue;const couldMatchDescendant=rule.target.startsWith(prefix)||rule.target==="**"||rule.target==="*";if(!couldMatchDescendant)continue;if(rule.target.startsWith(prefix)&&conditionMatches(rule.condition)){return true}const probePaths=[`${targetPath}.__probe__`];if(rule.target.startsWith(prefix)){const suffix=rule.target.slice(prefix.length);const firstSegment=suffix.split(".")[0];if(firstSegment&&!/[*!?{}]/u.test(firstSegment)){probePaths.unshift(`${targetPath}.${firstSegment}`);probePaths.push(`${targetPath}.${firstSegment}.__probe__`)}}for(const probePath of probePaths){if(permissionManager.checkAccess(callerPath,probePath,callerFilePath,null,runtimeContext,{useCache:false})){return true}}}return false};const createInternalRouteProxy=(value,routePath,seen=new WeakMap)=>{if(!value||typeof value!=="object"&&typeof value!=="function")return value;const isMetaProperty=prop=>prop==="__proto__"||prop==="prototype"||prop==="constructor"||prop==="caller"||prop==="arguments";let routeCache=seen.get(value);if(!routeCache){routeCache=new Map;seen.set(value,routeCache)}if(routeCache.has(routePath)){return routeCache.get(routePath)}const proxy=new Proxy(value,{get(target,prop,receiver){if(typeof prop!=="string"){const result2=Reflect.get(target,prop,receiver);return createInternalRouteProxy(result2,routePath,seen)}const childRoutePath=`${routePath}.${prop}`;let deniedError=null;try{enforceInternalPermission(childRoutePath)}catch(error){deniedError=error}if(deniedError){if(canTraverseInternalNamespace(childRoutePath)){const result2=Reflect.get(target,prop,receiver);if(result2&&(typeof result2==="object"||typeof result2==="function")){return createInternalRouteProxy(result2,childRoutePath,seen)}}throw deniedError}const result=Reflect.get(target,prop,receiver);if(isMetaProperty(prop)){return result}const descriptor=Object.getOwnPropertyDescriptor(target,prop);if(descriptor&&"value"in descriptor&&descriptor.configurable===false&&descriptor.writable===false){return descriptor.value}return createInternalRouteProxy(result,childRoutePath,seen)},getOwnPropertyDescriptor(target,prop){const descriptor=Reflect.getOwnPropertyDescriptor(target,prop);if(!descriptor)return void 0;if(typeof prop!=="string"){return descriptor}const childRoutePath=`${routePath}.${prop}`;if(isMetaProperty(prop)){enforceInternalPermission(childRoutePath);return descriptor}if("get"in descriptor||"set"in descriptor){enforceInternalPermission(childRoutePath);if(descriptor.configurable===true){return{...descriptor,get:typeof descriptor.get==="function"?function slothlet_internal_descriptor_getter(...args){enforceInternalPermission(childRoutePath);return Reflect.apply(descriptor.get,this,args)}:descriptor.get,set:typeof descriptor.set==="function"?function slothlet_internal_descriptor_setter(...args){enforceInternalPermission(childRoutePath);return Reflect.apply(descriptor.set,this,args)}:descriptor.set}}return descriptor}if(!("value"in descriptor)){return descriptor}const descriptorValue=descriptor.value;if(descriptor.configurable===false&&descriptor.writable===false){enforceInternalPermission(childRoutePath);return descriptor}if(!descriptorValue||typeof descriptorValue!=="object"&&typeof descriptorValue!=="function"||typeof descriptorValue==="function"){enforceInternalPermission(childRoutePath);if(typeof descriptorValue==="function"&&descriptor.configurable===true){return{...descriptor,value:createInternalRouteProxy(descriptorValue,childRoutePath,seen)}}return descriptor}return{...descriptor,value:createInternalRouteProxy(descriptorValue,childRoutePath,seen)}},set(target,prop,newValue,receiver){if(typeof prop!=="string"){return Reflect.set(target,prop,newValue,receiver)}const childRoutePath=`${routePath}.${prop}`;enforceInternalPermission(childRoutePath);return Reflect.set(target,prop,newValue,receiver)},defineProperty(target,prop,descriptor){if(typeof prop!=="string"){return Reflect.defineProperty(target,prop,descriptor)}const childRoutePath=`${routePath}.${prop}`;enforceInternalPermission(childRoutePath);return Reflect.defineProperty(target,prop,descriptor)},deleteProperty(target,prop){if(typeof prop!=="string"){return Reflect.deleteProperty(target,prop)}const childRoutePath=`${routePath}.${prop}`;enforceInternalPermission(childRoutePath);return Reflect.deleteProperty(target,prop)},ownKeys(target){return Reflect.ownKeys(target)},apply(target,thisArg,argArray){enforceInternalPermission(routePath);return Reflect.apply(target,thisArg,argArray)},construct(target,argArray,newTarget){enforceInternalPermission(routePath);return Reflect.construct(target,argArray,newTarget)}});routeCache.set(routePath,proxy);return proxy};let version="unknown";if(isNode){const pkg=loadJson(new URL("../../../package.json",import.meta.url));if(pkg?.version)version=pkg?.version}const namespace={i18n:{setLanguage,setLanguageAsync,getLanguage,translate,t,initI18n},version,instanceID:slothlet.instanceID,types:TYPE_STATES,api:{add:async function slothlet_api_add(apiPath,folderPath,options={},versionConfig=null){if(!config.api?.mutations?.add){throw new slothlet.SlothletError("INVALID_CONFIG_MUTATIONS_DISABLED",{operation:"api.add",validationError:true})}const{recordHistory:____recordHistory,collisionMode:____collisionMode,mutateExisting:____mutateExisting,...filteredOptions}=options;return slothlet.handlers.apiManager.addApiComponent({apiPath,folderPath,options:filteredOptions,versionConfig:versionConfig||null})},remove:async function slothlet_api_remove(pathOrModuleId){if(!config.api?.mutations?.remove){throw new slothlet.SlothletError("INVALID_CONFIG_MUTATIONS_DISABLED",{operation:"api.remove",validationError:true})}if(typeof pathOrModuleId!=="string"){throw new slothlet.SlothletError("INVALID_ARGUMENT",{argument:"pathOrModuleId",expected:"string",received:typeof pathOrModuleId,validationError:true})}return slothlet.handlers.apiManager.removeApiComponent(pathOrModuleId)},reload:async function slothlet_api_reload(pathOrModuleId,options){if(!config.api?.mutations?.reload){throw new slothlet.SlothletError("INVALID_CONFIG_MUTATIONS_DISABLED",{operation:"api.reload",validationError:true})}if(pathOrModuleId==null||pathOrModuleId===""||pathOrModuleId==="."){return slothlet.handlers.apiManager.reloadApiComponent({apiPath:".",options})}if(typeof pathOrModuleId!=="string"){throw new slothlet.SlothletError("INVALID_ARGUMENT",{argument:"pathOrModuleId",expected:"string, null, undefined, or '.'",received:typeof pathOrModuleId,validationError:true})}const isModuleId=slothlet.handlers.apiManager.state.addHistory.some(entry=>entry.moduleID===pathOrModuleId);if(isModuleId){return slothlet.handlers.apiManager.reloadApiComponent({moduleID:pathOrModuleId,options})}const normalizedPath=slothlet.handlers.apiManager.normalizeApiPath(pathOrModuleId).apiPath;const pathParts=normalizedPath.split(".");let current=slothlet.api;for(const part of pathParts){if(!current||typeof current!=="object"&&typeof current!=="function"){throw new slothlet.SlothletError("INVALID_API_PATH",{apiPath:pathOrModuleId,validationError:true})}current=current[part]}if(current===void 0){throw new slothlet.SlothletError("INVALID_API_PATH",{apiPath:pathOrModuleId,validationError:true})}return slothlet.handlers.apiManager.reloadApiComponent({apiPath:normalizedPath,options})},modules:{discover:function slothlet_modules_discover(options){return slothlet.handlers.moduleManager.discover(options)},sort:function slothlet_modules_sort(results,comparator){return slothlet.handlers.moduleManager.sort(results,comparator)},addModule:async function slothlet_modules_addModule(nameOrResult,options){if(!config.api?.mutations?.add){throw new slothlet.SlothletError("INVALID_CONFIG_MUTATIONS_DISABLED",{operation:"api.modules.addModule",validationError:true})}return slothlet.handlers.moduleManager.addModule(nameOrResult,options)},addModules:async function slothlet_modules_addModules(items,options){if(!config.api?.mutations?.add){throw new slothlet.SlothletError("INVALID_CONFIG_MUTATIONS_DISABLED",{operation:"api.modules.addModules",validationError:true})}return slothlet.handlers.moduleManager.addModules(items,options)},removeModule:async function slothlet_modules_removeModule(name,opts){if(!config.api?.mutations?.remove){throw new slothlet.SlothletError("INVALID_CONFIG_MUTATIONS_DISABLED",{operation:"api.modules.removeModule",validationError:true})}return slothlet.handlers.moduleManager.removeModule(name,opts)},addDiscovered:async function slothlet_modules_addDiscovered(options={}){if(!config.api?.mutations?.add){throw new slothlet.SlothletError("INVALID_CONFIG_MUTATIONS_DISABLED",{operation:"api.modules.addDiscovered",validationError:true})}const{sort:comparator,collisionMode,onFailure,concurrency,...discoverOptions}=options;const found=await slothlet.handlers.moduleManager.discover(discoverOptions);const ordered=slothlet.handlers.moduleManager.sort(found,comparator);return slothlet.handlers.moduleManager.addModules(ordered,{collisionMode,onFailure,concurrency})},getDiscoveryCache:function slothlet_modules_getDiscoveryCache(){return slothlet.handlers.moduleManager.getDiscoveryCache()},clearDiscoveryCache:function slothlet_modules_clearDiscoveryCache(){return slothlet.handlers.moduleManager.clearDiscoveryCache()},getStaleMounts:function slothlet_modules_getStaleMounts(){return slothlet.handlers.moduleManager.getStaleMounts()}}},sanitize:function slothlet_sanitize(str){if(typeof str!=="string"){throw new slothlet.SlothletError("INVALID_ARGUMENT",{argument:"str",expected:"string",received:typeof str,validationError:true})}return slothlet.helpers.sanitize.sanitizePropertyName(str,slothlet.config.sanitize||{})},lockCaller:function slothlet_lockCaller(fn){if(typeof fn!=="function"){throw new slothlet.SlothletError("INVALID_ARGUMENT",{argument:"fn",expected:"function",received:typeof fn,validationError:true})}const capturedWrapper=slothlet.contextManager?.tryGetContext?.()?.currentWrapper??null;if(!capturedWrapper)return fn;const locked=function slothlet_lockedCaller(...args){return slothlet.contextManager.runInContext(slothlet.instanceID,fn,this,args,capturedWrapper,true)};locked._slothletOriginal=fn;return locked},bind:function slothlet_bind(fn){if(typeof fn!=="function"){throw new slothlet.SlothletError("INVALID_ARGUMENT",{argument:"fn",expected:"function",received:typeof fn,validationError:true})}return AsyncResource?AsyncResource.bind(fn,"slothlet-bound"):fn},context:{get:key=>{if(slothlet.contextManager.constructor.name==="LiveContextManager"){const currentID=slothlet.contextManager.currentInstanceID;if(currentID){const activeStore=slothlet.contextManager.instances.get(currentID);const isOurInstance=currentID===slothlet.instanceID||currentID?.startsWith(slothlet.instanceID+"__run_")||activeStore?.parentInstanceID===slothlet.instanceID;if(isOurInstance&&activeStore){return key?activeStore.context[key]:{...activeStore.context}}}const store=slothlet.contextManager.instances.get(slothlet.instanceID);if(!store){const baseContext2=slothlet.context||{};return key?baseContext2[key]:{...baseContext2}}return key?store.context[key]:{...store.context}}if(slothlet.contextManager.constructor.name==="AsyncContextManager"){let currentStore=slothlet.contextManager.tryGetContext();if(!currentStore){const baseStore2=slothlet.contextManager.instances.get(slothlet.instanceID);const baseContext3=baseStore2?.context||{};return key?baseContext3[key]:{...baseContext3}}const isOurInstance=currentStore.instanceID===slothlet.instanceID||currentStore.parentInstanceID===slothlet.instanceID||currentStore.instanceID.startsWith(slothlet.instanceID+"__run_");if(isOurInstance){return key?currentStore.context[key]:{...currentStore.context}}const baseStore=slothlet.contextManager.instances.get(slothlet.instanceID);const baseContext2=baseStore?.context||{};return key?baseContext2[key]:{...baseContext2}}const baseContext=slothlet.context||{};return key?baseContext[key]:{...baseContext}},diagnostics:()=>{if(!slothlet.config?.diagnostics)return void 0;const managerType=slothlet.contextManager.constructor.name;const result={instanceID:slothlet.instanceID,managerType,instancesMapSize:slothlet.contextManager.instances.size,instancesMapKeys:Array.from(slothlet.contextManager.instances.keys()),baseContext:slothlet.context};const store=slothlet.contextManager.instances.get(slothlet.instanceID);result.storeFromInstancesMap=store?{instanceID:store.instanceID,context:store.context,createdAt:store.createdAt}:null;if(managerType==="AsyncContextManager"){try{const currentCtx=slothlet.contextManager.tryGetContext();result.currentALSContext=currentCtx?{instanceID:currentCtx.instanceID,context:currentCtx.context,hasParent:!!currentCtx.parentContext,parentInstanceID:currentCtx.parentInstanceID}:null}catch(____error){result.currentALSContext=null}}if(managerType==="LiveContextManager"){result.currentInstanceID=slothlet.contextManager.currentInstanceID}return result},run:this.createRunFunction(),scope:this.createScopeFunction()},hook:{on:function slothlet_hook_on(typePattern,handler,options={}){if(!slothlet.handlers?.hookManager){throw new slothlet.SlothletError("HOOKS_NOT_INITIALIZED",{validationError:true})}return slothlet.handlers.hookManager.on(typePattern,handler,options)},remove:function slothlet_hook_remove(filter={}){if(!slothlet.handlers?.hookManager){throw new slothlet.SlothletError("HOOKS_NOT_INITIALIZED",{validationError:true})}return slothlet.handlers.hookManager.remove(filter)},clear:function slothlet_hook_clear(filter={}){return this.remove(filter)},off:function slothlet_hook_off(idOrFilter){if(!slothlet.handlers?.hookManager){throw new slothlet.SlothletError("HOOKS_NOT_INITIALIZED",{validationError:true})}const filter=typeof idOrFilter==="string"?{id:idOrFilter}:idOrFilter;return slothlet.handlers.hookManager.remove(filter)},enable:function slothlet_hook_enable(filter={}){if(!slothlet.handlers?.hookManager){throw new slothlet.SlothletError("HOOKS_NOT_INITIALIZED",{validationError:true})}return slothlet.handlers.hookManager.enable(filter)},disable:function slothlet_hook_disable(filter={}){if(!slothlet.handlers?.hookManager){throw new slothlet.SlothletError("HOOKS_NOT_INITIALIZED",{validationError:true})}return slothlet.handlers.hookManager.disable(filter)},enablePattern:function slothlet_hook_enablePattern(pattern){if(!slothlet.handlers?.hookManager){throw new slothlet.SlothletError("HOOKS_NOT_INITIALIZED",{validationError:true})}return slothlet.handlers.hookManager.enablePattern(pattern)},disablePattern:function slothlet_hook_disablePattern(pattern){if(!slothlet.handlers?.hookManager){throw new slothlet.SlothletError("HOOKS_NOT_INITIALIZED",{validationError:true})}return slothlet.handlers.hookManager.disablePattern(pattern)},resetPatternFilter:function slothlet_hook_resetPatternFilter(){if(!slothlet.handlers?.hookManager){throw new slothlet.SlothletError("HOOKS_NOT_INITIALIZED",{validationError:true})}return slothlet.handlers.hookManager.resetPatternFilter()},list:function slothlet_hook_list(filter={}){if(!slothlet.handlers?.hookManager){throw new slothlet.SlothletError("HOOKS_NOT_INITIALIZED",{validationError:true})}return slothlet.handlers.hookManager.list(filter)}},metadata:{setGlobal:function slothlet_metadata_setGlobal(keyOrObj,value){if(!slothlet.handlers?.metadata){throw new slothlet.SlothletError("METADATA_NOT_AVAILABLE",{handlersKeys:slothlet.handlers?Object.keys(slothlet.handlers).join(", "):"undefined",validationError:true})}const validateGlobalMetadataKeyPath=keyPath=>{const blocked=new Set(["__proto__","prototype","constructor"]);if(typeof keyPath!=="string"||keyPath.length===0){throw new slothlet.SlothletError("INVALID_METADATA_KEY",{key:keyPath,type:typeof keyPath,expected:"non-empty string"})}const segments=keyPath.split(".");for(const segment of segments){if(!segment||blocked.has(segment)){throw new slothlet.SlothletError("INVALID_METADATA_KEY",{key:keyPath,type:typeof keyPath,expected:"safe dot-notation key without reserved segments"})}}};const normalizeGlobalMetadataObject=(source,prefix="",ancestors=new WeakSet)=>{if(ancestors.has(source)){throw new slothlet.SlothletError("INVALID_ARGUMENT",{argument:"keyOrObj",expected:"acyclic object",received:"circular reference",validationError:true})}ancestors.add(source);try{const normalized={};for(const[key,nestedValue]of Object.entries(source)){const fullKey=prefix?`${prefix}.${key}`:key;validateGlobalMetadataKeyPath(fullKey);const nestedProto=nestedValue&&typeof nestedValue==="object"?Object.getPrototypeOf(nestedValue):null;const isPlainNested=nestedProto===Object.prototype||nestedProto===null;if(nestedValue&&typeof nestedValue==="object"&&!Array.isArray(nestedValue)&&isPlainNested){normalized[key]=normalizeGlobalMetadataObject(nestedValue,fullKey,ancestors);continue}normalized[key]=nestedValue}return normalized}finally{ancestors.delete(source)}};if(keyOrObj&&typeof keyOrObj==="object"&&!Array.isArray(keyOrObj)){const normalizedMetadata=normalizeGlobalMetadataObject(keyOrObj);for(const[key,nestedValue]of Object.entries(normalizedMetadata)){slothlet.handlers.metadata.setGlobalMetadata(key,nestedValue)}return}if(typeof keyOrObj!=="string"){throw new slothlet.SlothletError("INVALID_ARGUMENT",{argument:"keyOrObj",expected:"string or object",received:typeof keyOrObj,validationError:true})}validateGlobalMetadataKeyPath(keyOrObj);return slothlet.handlers.metadata.setGlobalMetadata(keyOrObj,value)},set:function slothlet_metadata_set(fn,key,value){if(!slothlet.handlers?.metadata){throw new slothlet.SlothletError("METADATA_NOT_AVAILABLE",{handlersKeys:slothlet.handlers?Object.keys(slothlet.handlers).join(", "):"undefined",validationError:true})}return slothlet.handlers.metadata.setUserMetadata(fn,key,value)},remove:function slothlet_metadata_remove(fn,key){return slothlet.handlers.metadata.removeUserMetadata(fn,key)},setFor:function slothlet_metadata_setFor(pathOrModuleId,keyOrObj,value){if(!slothlet.handlers?.metadata){throw new slothlet.SlothletError("METADATA_NOT_AVAILABLE",{handlersKeys:slothlet.handlers?Object.keys(slothlet.handlers).join(", "):"undefined",validationError:true})}const resolvedPath=_resolvePathOrModuleId(slothlet,pathOrModuleId);return slothlet.handlers.metadata.setPathMetadata(resolvedPath,keyOrObj,value)},removeFor:function slothlet_metadata_removeFor(pathOrModuleId,key){if(!slothlet.handlers?.metadata)return;const resolvedPath=_resolvePathOrModuleId(slothlet,pathOrModuleId);return slothlet.handlers.metadata.removePathMetadata(resolvedPath,key)},getFor:function slothlet_metadata_getFor(pathOrModuleId){if(!slothlet.handlers?.metadata)return{};const resolvedPath=_resolvePathOrModuleId(slothlet,pathOrModuleId);return slothlet.handlers.metadata.getPathMetadata(resolvedPath)},setForVersion:function slothlet_metadata_setForVersion(logicalPath,versionTag,keyOrObj,value){if(!slothlet.handlers?.metadata){throw new slothlet.SlothletError("METADATA_NOT_AVAILABLE",{handlersKeys:slothlet.handlers?Object.keys(slothlet.handlers).join(", "):"undefined",validationError:true})}const info=slothlet.handlers?.versionManager?.list(logicalPath);if(!info||!info.versions?.[versionTag]){throw new slothlet.SlothletError("VERSION_NOT_FOUND",{version:versionTag,apiPath:logicalPath})}const{moduleID}=info.versions[versionTag];const resolvedPath=_resolvePathOrModuleId(slothlet,moduleID);return slothlet.handlers.metadata.setPathMetadata(resolvedPath,keyOrObj,value)},getForVersion:function slothlet_metadata_getForVersion(logicalPath,versionTag){if(!slothlet.handlers?.metadata)return{};const info=slothlet.handlers?.versionManager?.list(logicalPath);if(!info||!info.versions?.[versionTag])return{};const{moduleID}=info.versions[versionTag];const resolvedPath=_resolvePathOrModuleId(slothlet,moduleID);return slothlet.handlers.metadata.getPathMetadata(resolvedPath)}},scope:this.createScopeFunction(),run:this.createRunFunction(),reload:async(options={})=>{if(!config.api?.mutations?.reload){throw new slothlet.SlothletError("INVALID_CONFIG_MUTATIONS_DISABLED",{operation:"reload",validationError:true})}return slothlet.reload(options)},shutdown:async()=>{return slothlet.shutdown()},owner:{get:apiPath=>{if(slothlet.handlers?.ownership){return slothlet.handlers.ownership.getPathOwnership(apiPath)}return null}},materialize:(()=>{const mgr=slothlet.handlers?.materialize;const getMaterializedState=()=>{enforceInternalPermission("slothlet.materialize.materialized");return mgr?.materialized??false};const getMaterializeStats=()=>{enforceInternalPermission("slothlet.materialize.get");return mgr?mgr.get():{total:0,materialized:0,remaining:0,percentage:100}};const waitForMaterialization=async()=>{enforceInternalPermission("slothlet.materialize.wait");if(!mgr)return;return mgr.wait()};if(!mgr){return Object.freeze({get materialized(){return getMaterializedState()},get:getMaterializeStats,wait:waitForMaterialization})}return Object.freeze({get materialized(){return getMaterializedState()},get:getMaterializeStats,wait:waitForMaterialization})})(),lifecycle:(()=>{const handler=slothlet.handlers?.lifecycle;const noop=()=>{};if(!handler)return{on:noop,off:noop};return{on:handler.on.bind(handler),off:handler.off.bind(handler)}})(),env:slothlet.envSnapshot,versioning:{list:function slothlet_version_list(logicalPath){if(!slothlet.handlers?.versionManager)return void 0;return slothlet.handlers.versionManager.list(logicalPath)},setDefault:function slothlet_version_setDefault(logicalPath,versionTag){if(!slothlet.handlers?.versionManager)return;return slothlet.handlers.versionManager.setDefault(logicalPath,versionTag)},unregister:async function slothlet_version_unregister(logicalPath,versionTag){if(!slothlet.handlers?.versionManager)return false;const info=slothlet.handlers.versionManager.list(logicalPath);if(!info||!info.versions?.[versionTag])return false;const{moduleID:versionedModuleID}=info.versions[versionTag];await slothlet.handlers.apiManager.removeApiComponent(versionedModuleID);return true},getVersionMetadata:function slothlet_version_getVersionMetadata(logicalPath,versionTag){if(!slothlet.handlers?.versionManager)return void 0;return slothlet.handlers.versionManager.getVersionMetadataByPath(logicalPath,versionTag)},setVersionMetadata:function slothlet_version_setVersionMetadata(logicalPath,versionTag,patch){if(!slothlet.handlers?.versionManager)return;return slothlet.handlers.versionManager.setVersionMetadataByPath(logicalPath,versionTag,patch)}},permissions:{addRule:function slothlet_permissions_addRule(rule){if(!config.api?.mutations?.permissions){throw new slothlet.SlothletError("INVALID_CONFIG_MUTATIONS_DISABLED",{operation:"api.slothlet.permissions.addRule",validationError:true})}const permissionManager=slothlet.handlers?.permissionManager;if(!permissionManager?.addRule){throw new slothlet.SlothletError("PERMISSION_MANAGER_NOT_AVAILABLE",{validationError:true})}const ruleId=permissionManager.addRule(rule,null);if(slothlet.handlers?.apiManager?.state?.operationHistory){slothlet.handlers.apiManager.state.operationHistory.push({type:"addPermissionRule",rule,ownerModuleID:null,ruleId,timestamp:Date.now()})}return ruleId},removeRule:function slothlet_permissions_removeRule(ruleId){if(!config.api?.mutations?.permissions){throw new slothlet.SlothletError("INVALID_CONFIG_MUTATIONS_DISABLED",{operation:"api.slothlet.permissions.removeRule",validationError:true})}const permissionManager=slothlet.handlers?.permissionManager;if(!permissionManager?.removeRule){throw new slothlet.SlothletError("PERMISSION_MANAGER_NOT_AVAILABLE",{validationError:true})}const ctx=slothlet.contextManager?.tryGetContext?.();const currentWrapper=ctx?.currentWrapper;const callerModuleID=currentWrapper?.____slothletInternal?.moduleID??null;const result=slothlet.handlers.permissionManager.removeRule(ruleId,callerModuleID);if(result&&slothlet.handlers?.apiManager?.state?.operationHistory){slothlet.handlers.apiManager.state.operationHistory.push({type:"removePermissionRule",ruleId,callerModuleID,timestamp:Date.now()})}return result},self:{access:function slothlet_permissions_self_access(target){const permissionManager=slothlet.handlers?.permissionManager;if(!permissionManager?.checkAccess){throw new slothlet.SlothletError("PERMISSION_MANAGER_NOT_AVAILABLE",{validationError:true})}const ctx=slothlet.contextManager?.tryGetContext?.();const currentWrapper=ctx?.currentWrapper;const callerPath=currentWrapper?.____slothletInternal?.apiPath??"";const callerFilePath=currentWrapper?.____slothletInternal?.filePath??null;const runtimeContext=ctx?.context??null;return slothlet.handlers.permissionManager.checkAccess(callerPath,target,callerFilePath,null,runtimeContext)},rules:function slothlet_permissions_self_rules(){const permissionManager=slothlet.handlers?.permissionManager;if(!permissionManager?.getRulesForCaller){throw new slothlet.SlothletError("PERMISSION_MANAGER_NOT_AVAILABLE",{validationError:true})}const currentWrapper=slothlet.contextManager?.tryGetContext?.()?.currentWrapper;const callerPath=currentWrapper?.____slothletInternal?.apiPath??"";return slothlet.handlers.permissionManager.getRulesForCaller(callerPath)}},global:{checkAccess:function slothlet_permissions_global_checkAccess(caller,target){const permissionManager=slothlet.handlers?.permissionManager;if(!permissionManager?.checkAccess){throw new slothlet.SlothletError("PERMISSION_MANAGER_NOT_AVAILABLE",{validationError:true})}const runtimeContext=slothlet.contextManager?.tryGetContext?.()?.context??null;return slothlet.handlers.permissionManager.checkAccess(caller,target,null,null,runtimeContext)},rulesForPath:function slothlet_permissions_global_rulesForPath(path){const permissionManager=slothlet.handlers?.permissionManager;if(!permissionManager?.getRulesForPath){throw new slothlet.SlothletError("PERMISSION_MANAGER_NOT_AVAILABLE",{validationError:true})}return slothlet.handlers.permissionManager.getRulesForPath(path)},rulesByModule:function slothlet_permissions_global_rulesByModule(moduleID){const permissionManager=slothlet.handlers?.permissionManager;if(!permissionManager?.getRulesByModule){throw new slothlet.SlothletError("PERMISSION_MANAGER_NOT_AVAILABLE",{validationError:true})}return slothlet.handlers.permissionManager.getRulesByModule(moduleID)}},control:{get enabled(){const permissionManager=slothlet.handlers?.permissionManager;if(!permissionManager?.isEnabled){throw new slothlet.SlothletError("PERMISSION_MANAGER_NOT_AVAILABLE",{validationError:true})}return permissionManager.isEnabled()},enable:function slothlet_permissions_control_enable(){const permissionManager=slothlet.handlers?.permissionManager;if(!permissionManager?.enable){throw new slothlet.SlothletError("PERMISSION_MANAGER_NOT_AVAILABLE",{validationError:true})}slothlet.handlers.permissionManager.enable()},disable:function slothlet_permissions_control_disable(){const permissionManager=slothlet.handlers?.permissionManager;if(!permissionManager?.disable){throw new slothlet.SlothletError("PERMISSION_MANAGER_NOT_AVAILABLE",{validationError:true})}slothlet.handlers.permissionManager.disable()},get readGatingEnabled(){const permissionManager=slothlet.handlers?.permissionManager;if(!permissionManager?.isReadGatingEnabled){throw new slothlet.SlothletError("PERMISSION_MANAGER_NOT_AVAILABLE",{validationError:true})}return permissionManager.isReadGatingEnabled()},readGating:function slothlet_permissions_control_readGating(value){const permissionManager=slothlet.handlers?.permissionManager;if(!permissionManager?.setReadGating){throw new slothlet.SlothletError("PERMISSION_MANAGER_NOT_AVAILABLE",{validationError:true})}slothlet.handlers.permissionManager.setReadGating(value)}}}};if(!config.hook?.enabled&&config.diagnostics!==true){delete namespace.hooks}if(config.diagnostics===true){namespace.diag={describe:(showAll=false)=>{if(showAll){return{...userApi}}return Reflect.ownKeys(userApi)},reference:slothlet.reference||null,context:slothlet.context||{},inspect:()=>{return slothlet.getDiagnostics()},getAPI:()=>{return slothlet.getAPI()},getOwnership:()=>{return slothlet.getOwnership()},owner:{get:apiPath=>{if(slothlet.handlers?.ownership){return slothlet.handlers.ownership.getPathOwnership(apiPath)}return null}},caches:{get:()=>{if(slothlet.handlers?.apiCacheManager){return slothlet.handlers.apiCacheManager.getCacheDiagnostics()}return{totalCaches:0,caches:[]}},getAllModuleIDs:()=>{if(slothlet.handlers?.apiCacheManager){return slothlet.handlers.apiCacheManager.getAllModuleIDs()}return[]},has:moduleID=>{if(slothlet.handlers?.apiCacheManager){return slothlet.handlers.apiCacheManager.has(moduleID)}return false}},SlothletWarning:slothlet.SlothletWarning,hook:slothlet.handlers?.hookManager?{get enabled(){return slothlet.handlers.hookManager.enabled},compilePattern:pattern=>{return slothlet.handlers.hookManager.getCompilePatternForDiagnostics()(pattern)}}:void 0}}return createInternalRouteProxy(namespace,"slothlet")}createShutdownFunction(){const slothlet=this.slothlet;const shutdownFunction={shutdown:async()=>{if(slothlet.userHooks?.shutdown&&typeof slothlet.userHooks.shutdown==="function"){await slothlet.userHooks.shutdown()}return slothlet.shutdown()}}.shutdown;return shutdownFunction}createRunFunction(){const slothlet=this.slothlet;const scopeFunc=this.createScopeFunction();const runFunction={run:async(contextData,callback,...args)=>{if(slothlet.config.scope===false){throw new slothlet.SlothletError("SCOPE_DISABLED",{},null,{validationError:true})}if(!contextData||typeof contextData!=="object"){throw new slothlet.SlothletError("SCOPE_INVALID_CONTEXT",{received:typeof contextData},null,{validationError:true})}if(typeof callback!=="function"){throw new slothlet.SlothletError("SCOPE_INVALID_CALLBACK",{received:typeof callback},null,{validationError:true})}return scopeFunc({context:contextData,fn:callback,args,merge:slothlet.config.scope?.merge||"shallow",isolation:slothlet.config.scope?.isolation||"partial"})}}.run;return runFunction}createScopeFunction(){const slothlet=this.slothlet;const scopeFunction={scope:async options=>{if(slothlet.config.scope===false){throw new slothlet.SlothletError("SCOPE_DISABLED",{},null,{validationError:true})}if(!options||typeof options!=="object"){throw new slothlet.SlothletError("SCOPE_INVALID_OPTIONS",{received:typeof options},null,{validationError:true})}if(!options.fn||typeof options.fn!=="function"){throw new slothlet.SlothletError("SCOPE_INVALID_FN",{received:typeof options?.fn},null,{validationError:true})}if(!options.context||typeof options.context!=="object"){throw new slothlet.SlothletError("SCOPE_INVALID_CONTEXT_OBJECT",{received:typeof options?.context},null,{validationError:true})}const{context:contextData,fn,args=[],merge="shallow",isolation}=options;if(merge!=="shallow"&&merge!=="deep"){throw new slothlet.SlothletError("SCOPE_INVALID_MERGE_STRATEGY",{merge},null,{validationError:true})}const isolationMode=isolation||slothlet.config.scope?.isolation||"partial";if(isolationMode!=="partial"&&isolationMode!=="full"){throw new slothlet.SlothletError("SCOPE_INVALID_ISOLATION_MODE",{isolationMode},null,{validationError:true})}const contextManager=slothlet.contextManager;if(!contextManager){throw new slothlet.SlothletError("NO_CONTEXT_MANAGER",{validationError:true})}const{utilities}=slothlet.helpers;if(contextManager.constructor.name==="LiveContextManager"){let currentStore=null;const currentID=contextManager.currentInstanceID;if(currentID){const activeStore=contextManager.instances.get(currentID);const isOurContext=currentID===slothlet.instanceID||activeStore?.parentInstanceID===slothlet.instanceID||currentID.startsWith(slothlet.instanceID+"__run_");if(isOurContext){currentStore=activeStore}}if(!currentStore){currentStore=contextManager.instances.get(slothlet.instanceID)}if(!currentStore){throw new slothlet.SlothletError("CONTEXT_NOT_FOUND",{instanceID:slothlet.instanceID,availableInstances:[...contextManager.instances.keys()].join(", ")||"none",validationError:true})}let mergedContext;if(merge==="deep"){mergedContext=utilities.deepMerge(currentStore.context,contextData);mergedContext=structuredClone(mergedContext)}else{const clonedParent=structuredClone(currentStore.context);mergedContext={...clonedParent,...contextData}}const childInstanceID=`${slothlet.instanceID}__run_${Date.now()}_${Math.random().toString(36).slice(2,9)}`;const childStore={instanceID:childInstanceID,context:mergedContext,self:isolationMode==="full"?makeCopyOnWriteSelf(currentStore.self):currentStore.self,config:currentStore.config,createdAt:currentStore.createdAt,parentInstanceID:slothlet.instanceID,currentWrapper:currentStore.currentWrapper,callerWrapper:currentStore.callerWrapper,slothlet:currentStore.slothlet};contextManager.instances.set(childInstanceID,childStore);const previousInstanceID=contextManager.currentInstanceID;try{contextManager.currentInstanceID=childInstanceID;return await fn(...args)}finally{contextManager.currentInstanceID=previousInstanceID;contextManager.instances.delete(childInstanceID)}}if(contextManager.constructor.name==="AsyncContextManager"){let currentStore=null;const activeStore=contextManager.tryGetContext();if(activeStore){const isOurContext=activeStore.instanceID===slothlet.instanceID||activeStore.parentInstanceID===slothlet.instanceID||activeStore.instanceID.startsWith(slothlet.instanceID+"__run_");if(isOurContext){currentStore=activeStore}}if(!currentStore){const baseStore=contextManager.instances.get(slothlet.instanceID);if(!baseStore){throw new slothlet.SlothletError("CONTEXT_NOT_FOUND",{instanceID:slothlet.instanceID,availableInstances:[...contextManager.instances.keys()].join(", ")||"none",validationError:true})}currentStore=baseStore}let mergedContext;if(merge==="deep"){mergedContext=utilities.deepMerge(currentStore.context,contextData);mergedContext=structuredClone(mergedContext)}else{const clonedParent=structuredClone(currentStore.context);mergedContext={...clonedParent,...contextData}}const childInstanceID=`${slothlet.instanceID}__run_${Date.now()}_${Math.random().toString(36).slice(2,9)}`;const childStore={instanceID:childInstanceID,context:mergedContext,self:isolationMode==="full"?makeCopyOnWriteSelf(currentStore.self):currentStore.self,config:currentStore.config,createdAt:currentStore.createdAt,parentInstanceID:slothlet.instanceID,currentWrapper:currentStore.currentWrapper,callerWrapper:currentStore.callerWrapper,slothlet:currentStore.slothlet};contextManager.instances.set(childInstanceID,childStore);try{return await contextManager.als.run(childStore,async()=>{return await fn(...args)})}finally{contextManager.instances.delete(childInstanceID)}}throw new slothlet.SlothletError("UNSUPPORTED_CONTEXT_MANAGER",{manager:contextManager.constructor.name,validationError:true})}}.scope;return scopeFunction}createDestroyFunction(api){const slothlet=this.slothlet;const destroyFunction={destroy:async()=>{if(slothlet.userHooks?.destroy&&typeof slothlet.userHooks.destroy==="function"){await slothlet.userHooks.destroy()}if(api&&typeof api.shutdown==="function"){await api.shutdown()}else{await slothlet.shutdown()}slothlet.isDestroyed=true;const objectsToClear=[api,slothlet.api].filter(obj=>obj&&typeof obj==="object");for(const obj of objectsToClear){const keys=Object.keys(obj);for(const key of keys){try{delete obj[key]}catch(_){}}}slothlet.api=null}}.destroy;return destroyFunction}attachBuiltins(userApi,builtins){Object.defineProperty(userApi,"slothlet",{value:builtins.slothlet,enumerable:true,writable:false,configurable:true});Object.defineProperty(userApi,"shutdown",{value:builtins.shutdown,enumerable:true,writable:false,configurable:true});if(builtins.destroy!==null){Object.defineProperty(userApi,"destroy",{value:builtins.destroy,enumerable:true,writable:false,configurable:true})}}}export{ApiBuilder};
17
+ import{isNode,AsyncResource,loadJson}from"@cldmv/slothlet/helpers/platform";import{ComponentBase}from"@cldmv/slothlet/factories/component-base";import{TYPE_STATES}from"@cldmv/slothlet/handlers/unified-wrapper";import{getLanguage,initI18n,setLanguage,setLanguageAsync,t,translate}from"@cldmv/slothlet/i18n";function _resolvePathOrModuleId(slothlet,pathOrModuleId){const history=slothlet.handlers?.apiManager?.state?.addHistory;if(history){let match=null;for(let i=history.length-1;i>=0;i--){const entry=history[i];if(entry?.moduleID===pathOrModuleId){match=entry;break}}if(match)return match.apiPath}return pathOrModuleId}function makeCopyOnWriteSelf(parentSelf){const overlay=new Map;const childViews=new Map;return new Proxy({},{get(_t,prop){if(overlay.has(prop))return overlay.get(prop);const real=parentSelf[prop];if(real!==null&&typeof real==="object"){let view=childViews.get(prop);if(view===void 0){view=makeCopyOnWriteSelf(real);childViews.set(prop,view)}return view}return real},set(_t,prop,value){overlay.set(prop,value);childViews.delete(prop);return true},has(_t,prop){return overlay.has(prop)||prop in parentSelf},deleteProperty(_t,prop){overlay.delete(prop);childViews.delete(prop);return true},ownKeys(){const keys=new Set(Reflect.ownKeys(parentSelf));for(const k of overlay.keys())keys.add(k);return[...keys]},getOwnPropertyDescriptor(_t,prop){if(overlay.has(prop)){return{value:overlay.get(prop),writable:true,enumerable:true,configurable:true}}const desc=Reflect.getOwnPropertyDescriptor(parentSelf,prop);return desc?{...desc,configurable:true}:void 0}})}class ApiBuilder extends ComponentBase{static slothletProperty="apiBuilder";constructor(slothlet){super(slothlet)}async buildFinalAPI(userApi){this.slothlet.debug("api",{key:"DEBUG_MODE_BUILD_FINAL_API_CALLED",diagnostics:this.____config.diagnostics,userApiKeys:Object.keys(userApi)});if(this.slothlet._ownBuiltins){for(const[key,ref]of Object.entries(this.slothlet._ownBuiltins)){if(ref&&Object.prototype.hasOwnProperty.call(userApi,key)&&userApi[key]===ref){try{delete userApi[key]}catch(_){}}}}this.slothlet.userHooks={shutdown:typeof userApi.shutdown==="function"?userApi.shutdown:null,destroy:typeof userApi.destroy==="function"?userApi.destroy:null};if(userApi.slothlet){new this.SlothletWarning("WARNING_RESERVED_PROPERTY_CONFLICT",{properties:"slothlet"})}const slothletNamespace=await this.createSlothletNamespace(userApi);this.slothlet.debug("api",{key:"DEBUG_MODE_SLOTHLET_NAMESPACE_CREATED",namespaceKeys:Object.keys(slothletNamespace),hasDiag:!!slothletNamespace.diag});const shutdownFn=this.createShutdownFunction();this.attachBuiltins(userApi,{slothlet:slothletNamespace,shutdown:shutdownFn,destroy:null});this.slothlet.debug("api",{key:"DEBUG_MODE_BUILT_INS_ATTACHED",userApiKeys:Object.keys(userApi),hasSlothlet:!!userApi.slothlet,hasDiag:!!userApi.slothlet?.diag});const destroyWithApi=this.createDestroyFunction(userApi);Object.defineProperty(userApi,"destroy",{value:destroyWithApi,enumerable:true,writable:false,configurable:true});this.slothlet._ownBuiltins={shutdown:shutdownFn,slothlet:slothletNamespace,destroy:destroyWithApi};return userApi}async createSlothletNamespace(userApi){const slothlet=this.slothlet;const config=this.____config;const enforceInternalPermission=targetPath=>{const ctx=slothlet.contextManager?.tryGetContext?.();const callerWrapper=ctx?.currentWrapper;if(!callerWrapper)return;const permissionManager=slothlet.handlers?.permissionManager;if(!permissionManager?.enforceAccess){throw new slothlet.SlothletError("PERMISSION_MANAGER_NOT_AVAILABLE",{validationError:true})}const callerPath=callerWrapper.____slothletInternal?.apiPath??"";const callerFilePath=callerWrapper.____slothletInternal?.filePath??null;const runtimeContext=ctx?.context??null;if(!permissionManager.enforceAccess(callerPath,targetPath,callerFilePath,null,runtimeContext)){throw new slothlet.SlothletError("PERMISSION_DENIED",{caller:callerPath,target:targetPath})}};const canTraverseInternalNamespace=targetPath=>{const ctx=slothlet.contextManager?.tryGetContext?.();const callerWrapper=ctx?.currentWrapper;if(!callerWrapper)return false;const permissionManager=slothlet.handlers?.permissionManager;if(!permissionManager?.getRulesForCaller||!permissionManager?.checkAccess){return false}const callerPath=callerWrapper.____slothletInternal?.apiPath??"";const callerFilePath=callerWrapper.____slothletInternal?.filePath??null;const runtimeContext=ctx?.context??null;const callerRules=permissionManager.getRulesForCaller(callerPath);const conditionMatches=condition=>typeof permissionManager.matchesCondition==="function"?permissionManager.matchesCondition(condition,runtimeContext):false;const prefix=`${targetPath}.`;for(const rule of callerRules){if(!rule||rule.effect!=="allow"||typeof rule.target!=="string")continue;const couldMatchDescendant=rule.target.startsWith(prefix)||rule.target==="**"||rule.target==="*";if(!couldMatchDescendant)continue;if(rule.target.startsWith(prefix)&&conditionMatches(rule.condition)){return true}const probePaths=[`${targetPath}.__probe__`];if(rule.target.startsWith(prefix)){const suffix=rule.target.slice(prefix.length);const firstSegment=suffix.split(".")[0];if(firstSegment&&!/[*!?{}]/u.test(firstSegment)){probePaths.unshift(`${targetPath}.${firstSegment}`);probePaths.push(`${targetPath}.${firstSegment}.__probe__`)}}for(const probePath of probePaths){if(permissionManager.checkAccess(callerPath,probePath,callerFilePath,null,runtimeContext,{useCache:false})){return true}}}return false};const createInternalRouteProxy=(value,routePath,seen=new WeakMap)=>{if(!value||typeof value!=="object"&&typeof value!=="function")return value;const isMetaProperty=prop=>prop==="__proto__"||prop==="prototype"||prop==="constructor"||prop==="caller"||prop==="arguments";let routeCache=seen.get(value);if(!routeCache){routeCache=new Map;seen.set(value,routeCache)}if(routeCache.has(routePath)){return routeCache.get(routePath)}const proxy=new Proxy(value,{get(target,prop,receiver){if(typeof prop!=="string"){const result2=Reflect.get(target,prop,receiver);return createInternalRouteProxy(result2,routePath,seen)}const childRoutePath=`${routePath}.${prop}`;let deniedError=null;try{enforceInternalPermission(childRoutePath)}catch(error){deniedError=error}if(deniedError){if(canTraverseInternalNamespace(childRoutePath)){const result2=Reflect.get(target,prop,receiver);if(result2&&(typeof result2==="object"||typeof result2==="function")){return createInternalRouteProxy(result2,childRoutePath,seen)}}throw deniedError}const result=Reflect.get(target,prop,receiver);if(isMetaProperty(prop)){return result}const descriptor=Object.getOwnPropertyDescriptor(target,prop);if(descriptor&&"value"in descriptor&&descriptor.configurable===false&&descriptor.writable===false){return descriptor.value}return createInternalRouteProxy(result,childRoutePath,seen)},getOwnPropertyDescriptor(target,prop){const descriptor=Reflect.getOwnPropertyDescriptor(target,prop);if(!descriptor)return void 0;if(typeof prop!=="string"){return descriptor}const childRoutePath=`${routePath}.${prop}`;if(isMetaProperty(prop)){enforceInternalPermission(childRoutePath);return descriptor}if("get"in descriptor||"set"in descriptor){enforceInternalPermission(childRoutePath);if(descriptor.configurable===true){return{...descriptor,get:typeof descriptor.get==="function"?function slothlet_internal_descriptor_getter(...args){enforceInternalPermission(childRoutePath);return Reflect.apply(descriptor.get,this,args)}:descriptor.get,set:typeof descriptor.set==="function"?function slothlet_internal_descriptor_setter(...args){enforceInternalPermission(childRoutePath);return Reflect.apply(descriptor.set,this,args)}:descriptor.set}}return descriptor}if(!("value"in descriptor)){return descriptor}const descriptorValue=descriptor.value;if(descriptor.configurable===false&&descriptor.writable===false){enforceInternalPermission(childRoutePath);return descriptor}if(!descriptorValue||typeof descriptorValue!=="object"&&typeof descriptorValue!=="function"||typeof descriptorValue==="function"){enforceInternalPermission(childRoutePath);if(typeof descriptorValue==="function"&&descriptor.configurable===true){return{...descriptor,value:createInternalRouteProxy(descriptorValue,childRoutePath,seen)}}return descriptor}return{...descriptor,value:createInternalRouteProxy(descriptorValue,childRoutePath,seen)}},set(target,prop,newValue,receiver){if(typeof prop!=="string"){return Reflect.set(target,prop,newValue,receiver)}const childRoutePath=`${routePath}.${prop}`;enforceInternalPermission(childRoutePath);return Reflect.set(target,prop,newValue,receiver)},defineProperty(target,prop,descriptor){if(typeof prop!=="string"){return Reflect.defineProperty(target,prop,descriptor)}const childRoutePath=`${routePath}.${prop}`;enforceInternalPermission(childRoutePath);return Reflect.defineProperty(target,prop,descriptor)},deleteProperty(target,prop){if(typeof prop!=="string"){return Reflect.deleteProperty(target,prop)}const childRoutePath=`${routePath}.${prop}`;enforceInternalPermission(childRoutePath);return Reflect.deleteProperty(target,prop)},ownKeys(target){return Reflect.ownKeys(target)},apply(target,thisArg,argArray){enforceInternalPermission(routePath);return Reflect.apply(target,thisArg,argArray)},construct(target,argArray,newTarget){enforceInternalPermission(routePath);return Reflect.construct(target,argArray,newTarget)}});routeCache.set(routePath,proxy);return proxy};let version="unknown";if(isNode){const pkg=loadJson(new URL("../../../package.json",import.meta.url));if(pkg?.version)version=pkg?.version}const namespace={i18n:{setLanguage,setLanguageAsync,getLanguage,translate,t,initI18n},version,instanceID:slothlet.instanceID,types:TYPE_STATES,api:{add:async function slothlet_api_add(apiPath,folderPath,options={},versionConfig=null){if(!config.api?.mutations?.add){throw new slothlet.SlothletError("INVALID_CONFIG_MUTATIONS_DISABLED",{operation:"api.add",validationError:true})}const{recordHistory:____recordHistory,collisionMode:____collisionMode,mutateExisting:____mutateExisting,...filteredOptions}=options;return slothlet.handlers.apiManager.addApiComponent({apiPath,folderPath,options:filteredOptions,versionConfig:versionConfig||null})},remove:async function slothlet_api_remove(pathOrModuleId){if(!config.api?.mutations?.remove){throw new slothlet.SlothletError("INVALID_CONFIG_MUTATIONS_DISABLED",{operation:"api.remove",validationError:true})}if(typeof pathOrModuleId!=="string"){throw new slothlet.SlothletError("INVALID_ARGUMENT",{argument:"pathOrModuleId",expected:"string",received:typeof pathOrModuleId,validationError:true})}return slothlet.handlers.apiManager.removeApiComponent(pathOrModuleId)},reload:async function slothlet_api_reload(pathOrModuleId,options){if(!config.api?.mutations?.reload){throw new slothlet.SlothletError("INVALID_CONFIG_MUTATIONS_DISABLED",{operation:"api.reload",validationError:true})}if(pathOrModuleId==null||pathOrModuleId===""||pathOrModuleId==="."){return slothlet.handlers.apiManager.reloadApiComponent({apiPath:".",options})}if(typeof pathOrModuleId!=="string"){throw new slothlet.SlothletError("INVALID_ARGUMENT",{argument:"pathOrModuleId",expected:"string, null, undefined, or '.'",received:typeof pathOrModuleId,validationError:true})}const isModuleId=slothlet.handlers.apiManager.state.addHistory.some(entry=>entry.moduleID===pathOrModuleId);if(isModuleId){return slothlet.handlers.apiManager.reloadApiComponent({moduleID:pathOrModuleId,options})}const normalizedPath=slothlet.handlers.apiManager.normalizeApiPath(pathOrModuleId).apiPath;const pathParts=normalizedPath.split(".");let current=slothlet.api;for(const part of pathParts){if(!current||typeof current!=="object"&&typeof current!=="function"){throw new slothlet.SlothletError("INVALID_API_PATH",{apiPath:pathOrModuleId,validationError:true})}current=current[part]}if(current===void 0){throw new slothlet.SlothletError("INVALID_API_PATH",{apiPath:pathOrModuleId,validationError:true})}return slothlet.handlers.apiManager.reloadApiComponent({apiPath:normalizedPath,options})},modules:{discover:function slothlet_modules_discover(options){return slothlet.handlers.moduleManager.discover(options)},sort:function slothlet_modules_sort(results,comparator){return slothlet.handlers.moduleManager.sort(results,comparator)},addModule:async function slothlet_modules_addModule(nameOrResult,options){if(!config.api?.mutations?.add){throw new slothlet.SlothletError("INVALID_CONFIG_MUTATIONS_DISABLED",{operation:"api.modules.addModule",validationError:true})}return slothlet.handlers.moduleManager.addModule(nameOrResult,options)},addModules:async function slothlet_modules_addModules(items,options){if(!config.api?.mutations?.add){throw new slothlet.SlothletError("INVALID_CONFIG_MUTATIONS_DISABLED",{operation:"api.modules.addModules",validationError:true})}return slothlet.handlers.moduleManager.addModules(items,options)},removeModule:async function slothlet_modules_removeModule(name,opts){if(!config.api?.mutations?.remove){throw new slothlet.SlothletError("INVALID_CONFIG_MUTATIONS_DISABLED",{operation:"api.modules.removeModule",validationError:true})}return slothlet.handlers.moduleManager.removeModule(name,opts)},addDiscovered:async function slothlet_modules_addDiscovered(options={}){if(!config.api?.mutations?.add){throw new slothlet.SlothletError("INVALID_CONFIG_MUTATIONS_DISABLED",{operation:"api.modules.addDiscovered",validationError:true})}const{sort:comparator,collisionMode,onFailure,concurrency,...discoverOptions}=options;const found=await slothlet.handlers.moduleManager.discover(discoverOptions);const ordered=slothlet.handlers.moduleManager.sort(found,comparator);return slothlet.handlers.moduleManager.addModules(ordered,{collisionMode,onFailure,concurrency})},getDiscoveryCache:function slothlet_modules_getDiscoveryCache(){return slothlet.handlers.moduleManager.getDiscoveryCache()},clearDiscoveryCache:function slothlet_modules_clearDiscoveryCache(){return slothlet.handlers.moduleManager.clearDiscoveryCache()},getStaleMounts:function slothlet_modules_getStaleMounts(){return slothlet.handlers.moduleManager.getStaleMounts()}}},sanitize:function slothlet_sanitize(str){if(typeof str!=="string"){throw new slothlet.SlothletError("INVALID_ARGUMENT",{argument:"str",expected:"string",received:typeof str,validationError:true})}return slothlet.helpers.sanitize.sanitizePropertyName(str,slothlet.config.sanitize||{})},lockCaller:function slothlet_lockCaller(fn){if(typeof fn!=="function"){throw new slothlet.SlothletError("INVALID_ARGUMENT",{argument:"fn",expected:"function",received:typeof fn,validationError:true})}const capturedWrapper=slothlet.contextManager?.tryGetContext?.()?.currentWrapper??null;if(!capturedWrapper)return fn;const locked=function slothlet_lockedCaller(...args){return slothlet.contextManager.runInContext(slothlet.instanceID,fn,this,args,capturedWrapper,true)};locked._slothletOriginal=fn;return locked},bind:function slothlet_bind(fn){if(typeof fn!=="function"){throw new slothlet.SlothletError("INVALID_ARGUMENT",{argument:"fn",expected:"function",received:typeof fn,validationError:true})}return AsyncResource?AsyncResource.bind(fn,"slothlet-bound"):fn},context:{get:key=>{if(slothlet.contextManager.constructor.name==="LiveContextManager"){const currentID=slothlet.contextManager.currentInstanceID;if(currentID){const activeStore=slothlet.contextManager.instances.get(currentID);const isOurInstance=currentID===slothlet.instanceID||currentID?.startsWith(slothlet.instanceID+"__run_")||activeStore?.parentInstanceID===slothlet.instanceID;if(isOurInstance&&activeStore){return key?activeStore.context[key]:{...activeStore.context}}}const store=slothlet.contextManager.instances.get(slothlet.instanceID);if(!store){const baseContext2=slothlet.context||{};return key?baseContext2[key]:{...baseContext2}}return key?store.context[key]:{...store.context}}if(slothlet.contextManager.constructor.name==="AsyncContextManager"){let currentStore=slothlet.contextManager.tryGetContext();if(!currentStore){const baseStore2=slothlet.contextManager.instances.get(slothlet.instanceID);const baseContext3=baseStore2?.context||{};return key?baseContext3[key]:{...baseContext3}}const isOurInstance=currentStore.instanceID===slothlet.instanceID||currentStore.parentInstanceID===slothlet.instanceID||currentStore.instanceID.startsWith(slothlet.instanceID+"__run_");if(isOurInstance){return key?currentStore.context[key]:{...currentStore.context}}const baseStore=slothlet.contextManager.instances.get(slothlet.instanceID);const baseContext2=baseStore?.context||{};return key?baseContext2[key]:{...baseContext2}}const baseContext=slothlet.context||{};return key?baseContext[key]:{...baseContext}},diagnostics:()=>{if(!slothlet.config?.diagnostics)return void 0;const managerType=slothlet.contextManager.constructor.name;const result={instanceID:slothlet.instanceID,managerType,instancesMapSize:slothlet.contextManager.instances.size,instancesMapKeys:Array.from(slothlet.contextManager.instances.keys()),baseContext:slothlet.context};const store=slothlet.contextManager.instances.get(slothlet.instanceID);result.storeFromInstancesMap=store?{instanceID:store.instanceID,context:store.context,createdAt:store.createdAt}:null;if(managerType==="AsyncContextManager"){try{const currentCtx=slothlet.contextManager.tryGetContext();result.currentALSContext=currentCtx?{instanceID:currentCtx.instanceID,context:currentCtx.context,hasParent:!!currentCtx.parentContext,parentInstanceID:currentCtx.parentInstanceID}:null}catch(____error){result.currentALSContext=null}}if(managerType==="LiveContextManager"){result.currentInstanceID=slothlet.contextManager.currentInstanceID}return result},run:this.createRunFunction(),scope:this.createScopeFunction()},hook:{on:function slothlet_hook_on(typePattern,handler,options={}){if(!slothlet.handlers?.hookManager){throw new slothlet.SlothletError("HOOKS_NOT_INITIALIZED",{validationError:true})}return slothlet.handlers.hookManager.on(typePattern,handler,options)},remove:function slothlet_hook_remove(filter={}){if(!slothlet.handlers?.hookManager){throw new slothlet.SlothletError("HOOKS_NOT_INITIALIZED",{validationError:true})}return slothlet.handlers.hookManager.remove(filter)},clear:function slothlet_hook_clear(filter={}){return this.remove(filter)},off:function slothlet_hook_off(idOrFilter){if(!slothlet.handlers?.hookManager){throw new slothlet.SlothletError("HOOKS_NOT_INITIALIZED",{validationError:true})}const filter=typeof idOrFilter==="string"?{id:idOrFilter}:idOrFilter;return slothlet.handlers.hookManager.remove(filter)},enable:function slothlet_hook_enable(filter={}){if(!slothlet.handlers?.hookManager){throw new slothlet.SlothletError("HOOKS_NOT_INITIALIZED",{validationError:true})}return slothlet.handlers.hookManager.enable(filter)},disable:function slothlet_hook_disable(filter={}){if(!slothlet.handlers?.hookManager){throw new slothlet.SlothletError("HOOKS_NOT_INITIALIZED",{validationError:true})}return slothlet.handlers.hookManager.disable(filter)},enablePattern:function slothlet_hook_enablePattern(pattern){if(!slothlet.handlers?.hookManager){throw new slothlet.SlothletError("HOOKS_NOT_INITIALIZED",{validationError:true})}return slothlet.handlers.hookManager.enablePattern(pattern)},disablePattern:function slothlet_hook_disablePattern(pattern){if(!slothlet.handlers?.hookManager){throw new slothlet.SlothletError("HOOKS_NOT_INITIALIZED",{validationError:true})}return slothlet.handlers.hookManager.disablePattern(pattern)},resetPatternFilter:function slothlet_hook_resetPatternFilter(){if(!slothlet.handlers?.hookManager){throw new slothlet.SlothletError("HOOKS_NOT_INITIALIZED",{validationError:true})}return slothlet.handlers.hookManager.resetPatternFilter()},list:function slothlet_hook_list(filter={}){if(!slothlet.handlers?.hookManager){throw new slothlet.SlothletError("HOOKS_NOT_INITIALIZED",{validationError:true})}return slothlet.handlers.hookManager.list(filter)},pin:{get enabled(){if(!slothlet.handlers?.hookManager){throw new slothlet.SlothletError("HOOKS_NOT_INITIALIZED",{validationError:true})}return slothlet.handlers.hookManager.pinEnforced},enable:function slothlet_hook_pin_enable(){if(!slothlet.handlers?.hookManager){throw new slothlet.SlothletError("HOOKS_NOT_INITIALIZED",{validationError:true})}return slothlet.handlers.hookManager.setPinEnforced(true)},disable:function slothlet_hook_pin_disable(){if(!slothlet.handlers?.hookManager){throw new slothlet.SlothletError("HOOKS_NOT_INITIALIZED",{validationError:true})}return slothlet.handlers.hookManager.setPinEnforced(false)}}},metadata:{setGlobal:function slothlet_metadata_setGlobal(keyOrObj,value){if(!slothlet.handlers?.metadata){throw new slothlet.SlothletError("METADATA_NOT_AVAILABLE",{handlersKeys:slothlet.handlers?Object.keys(slothlet.handlers).join(", "):"undefined",validationError:true})}const validateGlobalMetadataKeyPath=keyPath=>{const blocked=new Set(["__proto__","prototype","constructor"]);if(typeof keyPath!=="string"||keyPath.length===0){throw new slothlet.SlothletError("INVALID_METADATA_KEY",{key:keyPath,type:typeof keyPath,expected:"non-empty string"})}const segments=keyPath.split(".");for(const segment of segments){if(!segment||blocked.has(segment)){throw new slothlet.SlothletError("INVALID_METADATA_KEY",{key:keyPath,type:typeof keyPath,expected:"safe dot-notation key without reserved segments"})}}};const normalizeGlobalMetadataObject=(source,prefix="",ancestors=new WeakSet)=>{if(ancestors.has(source)){throw new slothlet.SlothletError("INVALID_ARGUMENT",{argument:"keyOrObj",expected:"acyclic object",received:"circular reference",validationError:true})}ancestors.add(source);try{const normalized={};for(const[key,nestedValue]of Object.entries(source)){const fullKey=prefix?`${prefix}.${key}`:key;validateGlobalMetadataKeyPath(fullKey);const nestedProto=nestedValue&&typeof nestedValue==="object"?Object.getPrototypeOf(nestedValue):null;const isPlainNested=nestedProto===Object.prototype||nestedProto===null;if(nestedValue&&typeof nestedValue==="object"&&!Array.isArray(nestedValue)&&isPlainNested){normalized[key]=normalizeGlobalMetadataObject(nestedValue,fullKey,ancestors);continue}normalized[key]=nestedValue}return normalized}finally{ancestors.delete(source)}};if(keyOrObj&&typeof keyOrObj==="object"&&!Array.isArray(keyOrObj)){const normalizedMetadata=normalizeGlobalMetadataObject(keyOrObj);for(const[key,nestedValue]of Object.entries(normalizedMetadata)){slothlet.handlers.metadata.setGlobalMetadata(key,nestedValue)}return}if(typeof keyOrObj!=="string"){throw new slothlet.SlothletError("INVALID_ARGUMENT",{argument:"keyOrObj",expected:"string or object",received:typeof keyOrObj,validationError:true})}validateGlobalMetadataKeyPath(keyOrObj);return slothlet.handlers.metadata.setGlobalMetadata(keyOrObj,value)},set:function slothlet_metadata_set(fn,key,value){if(!slothlet.handlers?.metadata){throw new slothlet.SlothletError("METADATA_NOT_AVAILABLE",{handlersKeys:slothlet.handlers?Object.keys(slothlet.handlers).join(", "):"undefined",validationError:true})}return slothlet.handlers.metadata.setUserMetadata(fn,key,value)},remove:function slothlet_metadata_remove(fn,key){return slothlet.handlers.metadata.removeUserMetadata(fn,key)},setFor:function slothlet_metadata_setFor(pathOrModuleId,keyOrObj,value){if(!slothlet.handlers?.metadata){throw new slothlet.SlothletError("METADATA_NOT_AVAILABLE",{handlersKeys:slothlet.handlers?Object.keys(slothlet.handlers).join(", "):"undefined",validationError:true})}const resolvedPath=_resolvePathOrModuleId(slothlet,pathOrModuleId);return slothlet.handlers.metadata.setPathMetadata(resolvedPath,keyOrObj,value)},removeFor:function slothlet_metadata_removeFor(pathOrModuleId,key){if(!slothlet.handlers?.metadata)return;const resolvedPath=_resolvePathOrModuleId(slothlet,pathOrModuleId);return slothlet.handlers.metadata.removePathMetadata(resolvedPath,key)},getFor:function slothlet_metadata_getFor(pathOrModuleId){if(!slothlet.handlers?.metadata)return{};const resolvedPath=_resolvePathOrModuleId(slothlet,pathOrModuleId);return slothlet.handlers.metadata.getPathMetadata(resolvedPath)},setForVersion:function slothlet_metadata_setForVersion(logicalPath,versionTag,keyOrObj,value){if(!slothlet.handlers?.metadata){throw new slothlet.SlothletError("METADATA_NOT_AVAILABLE",{handlersKeys:slothlet.handlers?Object.keys(slothlet.handlers).join(", "):"undefined",validationError:true})}const info=slothlet.handlers?.versionManager?.list(logicalPath);if(!info||!info.versions?.[versionTag]){throw new slothlet.SlothletError("VERSION_NOT_FOUND",{version:versionTag,apiPath:logicalPath})}const{moduleID}=info.versions[versionTag];const resolvedPath=_resolvePathOrModuleId(slothlet,moduleID);return slothlet.handlers.metadata.setPathMetadata(resolvedPath,keyOrObj,value)},getForVersion:function slothlet_metadata_getForVersion(logicalPath,versionTag){if(!slothlet.handlers?.metadata)return{};const info=slothlet.handlers?.versionManager?.list(logicalPath);if(!info||!info.versions?.[versionTag])return{};const{moduleID}=info.versions[versionTag];const resolvedPath=_resolvePathOrModuleId(slothlet,moduleID);return slothlet.handlers.metadata.getPathMetadata(resolvedPath)}},scope:this.createScopeFunction(),run:this.createRunFunction(),reload:async(options={})=>{if(!config.api?.mutations?.reload){throw new slothlet.SlothletError("INVALID_CONFIG_MUTATIONS_DISABLED",{operation:"reload",validationError:true})}return slothlet.reload(options)},shutdown:async()=>{return slothlet.shutdown()},owner:{get:apiPath=>{if(slothlet.handlers?.ownership){return slothlet.handlers.ownership.getPathOwnership(apiPath)}return null}},materialize:(()=>{const mgr=slothlet.handlers?.materialize;const getMaterializedState=()=>{enforceInternalPermission("slothlet.materialize.materialized");return mgr?.materialized??false};const getMaterializeStats=()=>{enforceInternalPermission("slothlet.materialize.get");return mgr?mgr.get():{total:0,materialized:0,remaining:0,percentage:100}};const waitForMaterialization=async()=>{enforceInternalPermission("slothlet.materialize.wait");if(!mgr)return;return mgr.wait()};if(!mgr){return Object.freeze({get materialized(){return getMaterializedState()},get:getMaterializeStats,wait:waitForMaterialization})}return Object.freeze({get materialized(){return getMaterializedState()},get:getMaterializeStats,wait:waitForMaterialization})})(),lifecycle:(()=>{const handler=slothlet.handlers?.lifecycle;const noop=()=>{};if(!handler)return{on:noop,off:noop};return{on:handler.on.bind(handler),off:handler.off.bind(handler)}})(),env:slothlet.envSnapshot,versioning:{list:function slothlet_version_list(logicalPath){if(!slothlet.handlers?.versionManager)return void 0;return slothlet.handlers.versionManager.list(logicalPath)},setDefault:function slothlet_version_setDefault(logicalPath,versionTag){if(!slothlet.handlers?.versionManager)return;return slothlet.handlers.versionManager.setDefault(logicalPath,versionTag)},unregister:async function slothlet_version_unregister(logicalPath,versionTag){if(!slothlet.handlers?.versionManager)return false;const info=slothlet.handlers.versionManager.list(logicalPath);if(!info||!info.versions?.[versionTag])return false;const{moduleID:versionedModuleID}=info.versions[versionTag];await slothlet.handlers.apiManager.removeApiComponent(versionedModuleID);return true},getVersionMetadata:function slothlet_version_getVersionMetadata(logicalPath,versionTag){if(!slothlet.handlers?.versionManager)return void 0;return slothlet.handlers.versionManager.getVersionMetadataByPath(logicalPath,versionTag)},setVersionMetadata:function slothlet_version_setVersionMetadata(logicalPath,versionTag,patch){if(!slothlet.handlers?.versionManager)return;return slothlet.handlers.versionManager.setVersionMetadataByPath(logicalPath,versionTag,patch)}},permissions:{addRule:function slothlet_permissions_addRule(rule){if(!config.api?.mutations?.permissions){throw new slothlet.SlothletError("INVALID_CONFIG_MUTATIONS_DISABLED",{operation:"api.slothlet.permissions.addRule",validationError:true})}const permissionManager=slothlet.handlers?.permissionManager;if(!permissionManager?.addRule){throw new slothlet.SlothletError("PERMISSION_MANAGER_NOT_AVAILABLE",{validationError:true})}const ruleId=permissionManager.addRule(rule,null);if(slothlet.handlers?.apiManager?.state?.operationHistory){slothlet.handlers.apiManager.state.operationHistory.push({type:"addPermissionRule",rule,ownerModuleID:null,ruleId,timestamp:Date.now()})}return ruleId},removeRule:function slothlet_permissions_removeRule(ruleId){if(!config.api?.mutations?.permissions){throw new slothlet.SlothletError("INVALID_CONFIG_MUTATIONS_DISABLED",{operation:"api.slothlet.permissions.removeRule",validationError:true})}const permissionManager=slothlet.handlers?.permissionManager;if(!permissionManager?.removeRule){throw new slothlet.SlothletError("PERMISSION_MANAGER_NOT_AVAILABLE",{validationError:true})}const ctx=slothlet.contextManager?.tryGetContext?.();const currentWrapper=ctx?.currentWrapper;const callerModuleID=currentWrapper?.____slothletInternal?.moduleID??null;const result=slothlet.handlers.permissionManager.removeRule(ruleId,callerModuleID);if(result&&slothlet.handlers?.apiManager?.state?.operationHistory){slothlet.handlers.apiManager.state.operationHistory.push({type:"removePermissionRule",ruleId,callerModuleID,timestamp:Date.now()})}return result},self:{access:function slothlet_permissions_self_access(target){const permissionManager=slothlet.handlers?.permissionManager;if(!permissionManager?.checkAccess){throw new slothlet.SlothletError("PERMISSION_MANAGER_NOT_AVAILABLE",{validationError:true})}const ctx=slothlet.contextManager?.tryGetContext?.();const currentWrapper=ctx?.currentWrapper;const callerPath=currentWrapper?.____slothletInternal?.apiPath??"";const callerFilePath=currentWrapper?.____slothletInternal?.filePath??null;const runtimeContext=ctx?.context??null;return slothlet.handlers.permissionManager.checkAccess(callerPath,target,callerFilePath,null,runtimeContext)},rules:function slothlet_permissions_self_rules(){const permissionManager=slothlet.handlers?.permissionManager;if(!permissionManager?.getRulesForCaller){throw new slothlet.SlothletError("PERMISSION_MANAGER_NOT_AVAILABLE",{validationError:true})}const currentWrapper=slothlet.contextManager?.tryGetContext?.()?.currentWrapper;const callerPath=currentWrapper?.____slothletInternal?.apiPath??"";return slothlet.handlers.permissionManager.getRulesForCaller(callerPath)}},global:{checkAccess:function slothlet_permissions_global_checkAccess(caller,target){const permissionManager=slothlet.handlers?.permissionManager;if(!permissionManager?.checkAccess){throw new slothlet.SlothletError("PERMISSION_MANAGER_NOT_AVAILABLE",{validationError:true})}const runtimeContext=slothlet.contextManager?.tryGetContext?.()?.context??null;return slothlet.handlers.permissionManager.checkAccess(caller,target,null,null,runtimeContext)},rulesForPath:function slothlet_permissions_global_rulesForPath(path){const permissionManager=slothlet.handlers?.permissionManager;if(!permissionManager?.getRulesForPath){throw new slothlet.SlothletError("PERMISSION_MANAGER_NOT_AVAILABLE",{validationError:true})}return slothlet.handlers.permissionManager.getRulesForPath(path)},rulesByModule:function slothlet_permissions_global_rulesByModule(moduleID){const permissionManager=slothlet.handlers?.permissionManager;if(!permissionManager?.getRulesByModule){throw new slothlet.SlothletError("PERMISSION_MANAGER_NOT_AVAILABLE",{validationError:true})}return slothlet.handlers.permissionManager.getRulesByModule(moduleID)}},control:{get enabled(){const permissionManager=slothlet.handlers?.permissionManager;if(!permissionManager?.isEnabled){throw new slothlet.SlothletError("PERMISSION_MANAGER_NOT_AVAILABLE",{validationError:true})}return permissionManager.isEnabled()},enable:function slothlet_permissions_control_enable(){const permissionManager=slothlet.handlers?.permissionManager;if(!permissionManager?.enable){throw new slothlet.SlothletError("PERMISSION_MANAGER_NOT_AVAILABLE",{validationError:true})}slothlet.handlers.permissionManager.enable()},disable:function slothlet_permissions_control_disable(){const permissionManager=slothlet.handlers?.permissionManager;if(!permissionManager?.disable){throw new slothlet.SlothletError("PERMISSION_MANAGER_NOT_AVAILABLE",{validationError:true})}slothlet.handlers.permissionManager.disable()},get readGatingEnabled(){const permissionManager=slothlet.handlers?.permissionManager;if(!permissionManager?.isReadGatingEnabled){throw new slothlet.SlothletError("PERMISSION_MANAGER_NOT_AVAILABLE",{validationError:true})}return permissionManager.isReadGatingEnabled()},readGating:function slothlet_permissions_control_readGating(value){const permissionManager=slothlet.handlers?.permissionManager;if(!permissionManager?.setReadGating){throw new slothlet.SlothletError("PERMISSION_MANAGER_NOT_AVAILABLE",{validationError:true})}slothlet.handlers.permissionManager.setReadGating(value)}}}};if(!config.hook?.enabled&&config.diagnostics!==true){delete namespace.hooks}if(config.diagnostics===true){namespace.diag={describe:(showAll=false)=>{if(showAll){return{...userApi}}return Reflect.ownKeys(userApi)},reference:slothlet.reference||null,context:slothlet.context||{},inspect:()=>{return slothlet.getDiagnostics()},getAPI:()=>{return slothlet.getAPI()},getOwnership:()=>{return slothlet.getOwnership()},owner:{get:apiPath=>{if(slothlet.handlers?.ownership){return slothlet.handlers.ownership.getPathOwnership(apiPath)}return null}},caches:{get:()=>{if(slothlet.handlers?.apiCacheManager){return slothlet.handlers.apiCacheManager.getCacheDiagnostics()}return{totalCaches:0,caches:[]}},getAllModuleIDs:()=>{if(slothlet.handlers?.apiCacheManager){return slothlet.handlers.apiCacheManager.getAllModuleIDs()}return[]},has:moduleID=>{if(slothlet.handlers?.apiCacheManager){return slothlet.handlers.apiCacheManager.has(moduleID)}return false}},SlothletWarning:slothlet.SlothletWarning,hook:slothlet.handlers?.hookManager?{get enabled(){return slothlet.handlers.hookManager.enabled},compilePattern:pattern=>{return slothlet.handlers.hookManager.getCompilePatternForDiagnostics()(pattern)}}:void 0}}return createInternalRouteProxy(namespace,"slothlet")}createShutdownFunction(){const slothlet=this.slothlet;const shutdownFunction={shutdown:async()=>{if(slothlet.userHooks?.shutdown&&typeof slothlet.userHooks.shutdown==="function"){await slothlet.userHooks.shutdown()}return slothlet.shutdown()}}.shutdown;return shutdownFunction}createRunFunction(){const slothlet=this.slothlet;const scopeFunc=this.createScopeFunction();const runFunction={run:async(contextData,callback,...args)=>{if(slothlet.config.scope===false){throw new slothlet.SlothletError("SCOPE_DISABLED",{},null,{validationError:true})}if(!contextData||typeof contextData!=="object"){throw new slothlet.SlothletError("SCOPE_INVALID_CONTEXT",{received:typeof contextData},null,{validationError:true})}if(typeof callback!=="function"){throw new slothlet.SlothletError("SCOPE_INVALID_CALLBACK",{received:typeof callback},null,{validationError:true})}return scopeFunc({context:contextData,fn:callback,args,merge:slothlet.config.scope?.merge||"shallow",isolation:slothlet.config.scope?.isolation||"partial"})}}.run;return runFunction}createScopeFunction(){const slothlet=this.slothlet;const scopeFunction={scope:async options=>{if(slothlet.config.scope===false){throw new slothlet.SlothletError("SCOPE_DISABLED",{},null,{validationError:true})}if(!options||typeof options!=="object"){throw new slothlet.SlothletError("SCOPE_INVALID_OPTIONS",{received:typeof options},null,{validationError:true})}if(!options.fn||typeof options.fn!=="function"){throw new slothlet.SlothletError("SCOPE_INVALID_FN",{received:typeof options?.fn},null,{validationError:true})}if(!options.context||typeof options.context!=="object"){throw new slothlet.SlothletError("SCOPE_INVALID_CONTEXT_OBJECT",{received:typeof options?.context},null,{validationError:true})}const{context:contextData,fn,args=[],merge="shallow",isolation}=options;if(merge!=="shallow"&&merge!=="deep"){throw new slothlet.SlothletError("SCOPE_INVALID_MERGE_STRATEGY",{merge},null,{validationError:true})}const isolationMode=isolation||slothlet.config.scope?.isolation||"partial";if(isolationMode!=="partial"&&isolationMode!=="full"){throw new slothlet.SlothletError("SCOPE_INVALID_ISOLATION_MODE",{isolationMode},null,{validationError:true})}const contextManager=slothlet.contextManager;if(!contextManager){throw new slothlet.SlothletError("NO_CONTEXT_MANAGER",{validationError:true})}const{utilities}=slothlet.helpers;if(contextManager.constructor.name==="LiveContextManager"){let currentStore=null;const currentID=contextManager.currentInstanceID;if(currentID){const activeStore=contextManager.instances.get(currentID);const isOurContext=currentID===slothlet.instanceID||activeStore?.parentInstanceID===slothlet.instanceID||currentID.startsWith(slothlet.instanceID+"__run_");if(isOurContext){currentStore=activeStore}}if(!currentStore){currentStore=contextManager.instances.get(slothlet.instanceID)}if(!currentStore){throw new slothlet.SlothletError("CONTEXT_NOT_FOUND",{instanceID:slothlet.instanceID,availableInstances:[...contextManager.instances.keys()].join(", ")||"none",validationError:true})}let mergedContext;if(merge==="deep"){mergedContext=utilities.deepMerge(currentStore.context,contextData);mergedContext=structuredClone(mergedContext)}else{const clonedParent=structuredClone(currentStore.context);mergedContext={...clonedParent,...contextData}}const childInstanceID=`${slothlet.instanceID}__run_${Date.now()}_${Math.random().toString(36).slice(2,9)}`;const childStore={instanceID:childInstanceID,context:mergedContext,self:isolationMode==="full"?makeCopyOnWriteSelf(currentStore.self):currentStore.self,config:currentStore.config,createdAt:currentStore.createdAt,parentInstanceID:slothlet.instanceID,currentWrapper:currentStore.currentWrapper,callerWrapper:currentStore.callerWrapper,slothlet:currentStore.slothlet};contextManager.instances.set(childInstanceID,childStore);const previousInstanceID=contextManager.currentInstanceID;try{contextManager.currentInstanceID=childInstanceID;return await fn(...args)}finally{contextManager.currentInstanceID=previousInstanceID;contextManager.instances.delete(childInstanceID)}}if(contextManager.constructor.name==="AsyncContextManager"){let currentStore=null;const activeStore=contextManager.tryGetContext();if(activeStore){const isOurContext=activeStore.instanceID===slothlet.instanceID||activeStore.parentInstanceID===slothlet.instanceID||activeStore.instanceID.startsWith(slothlet.instanceID+"__run_");if(isOurContext){currentStore=activeStore}}if(!currentStore){const baseStore=contextManager.instances.get(slothlet.instanceID);if(!baseStore){throw new slothlet.SlothletError("CONTEXT_NOT_FOUND",{instanceID:slothlet.instanceID,availableInstances:[...contextManager.instances.keys()].join(", ")||"none",validationError:true})}currentStore=baseStore}let mergedContext;if(merge==="deep"){mergedContext=utilities.deepMerge(currentStore.context,contextData);mergedContext=structuredClone(mergedContext)}else{const clonedParent=structuredClone(currentStore.context);mergedContext={...clonedParent,...contextData}}const childInstanceID=`${slothlet.instanceID}__run_${Date.now()}_${Math.random().toString(36).slice(2,9)}`;const childStore={instanceID:childInstanceID,context:mergedContext,self:isolationMode==="full"?makeCopyOnWriteSelf(currentStore.self):currentStore.self,config:currentStore.config,createdAt:currentStore.createdAt,parentInstanceID:slothlet.instanceID,currentWrapper:currentStore.currentWrapper,callerWrapper:currentStore.callerWrapper,slothlet:currentStore.slothlet};contextManager.instances.set(childInstanceID,childStore);try{return await contextManager.als.run(childStore,async()=>{return await fn(...args)})}finally{contextManager.instances.delete(childInstanceID)}}throw new slothlet.SlothletError("UNSUPPORTED_CONTEXT_MANAGER",{manager:contextManager.constructor.name,validationError:true})}}.scope;return scopeFunction}createDestroyFunction(api){const slothlet=this.slothlet;const destroyFunction={destroy:async()=>{if(slothlet.userHooks?.destroy&&typeof slothlet.userHooks.destroy==="function"){await slothlet.userHooks.destroy()}if(api&&typeof api.shutdown==="function"){await api.shutdown()}else{await slothlet.shutdown()}slothlet.isDestroyed=true;const objectsToClear=[api,slothlet.api].filter(obj=>obj&&typeof obj==="object");for(const obj of objectsToClear){const keys=Object.keys(obj);for(const key of keys){try{delete obj[key]}catch(_){}}}slothlet.api=null}}.destroy;return destroyFunction}attachBuiltins(userApi,builtins){Object.defineProperty(userApi,"slothlet",{value:builtins.slothlet,enumerable:true,writable:false,configurable:true});Object.defineProperty(userApi,"shutdown",{value:builtins.shutdown,enumerable:true,writable:false,configurable:true});if(builtins.destroy!==null){Object.defineProperty(userApi,"destroy",{value:builtins.destroy,enumerable:true,writable:false,configurable:true})}}}export{ApiBuilder};
@@ -14,4 +14,4 @@
14
14
  limitations under the License.
15
15
  */
16
16
 
17
- import{ComponentBase}from"@cldmv/slothlet/factories/component-base";class Builder extends ComponentBase{static slothletProperty="builder";constructor(slothlet){super(slothlet)}async buildAPI(options){const{dir,mode="eager",apiPathPrefix="",collisionContext="initial",moduleID,cacheBust=null,fileFilter=null,collisionMode=null}=options;if(!dir||typeof dir!=="string"){throw new this.SlothletError("INVALID_CONFIG_DIR_INVALID",{dir},null,{validationError:true})}if(mode!=="eager"&&mode!=="lazy"){throw new this.SlothletError("INVALID_CONFIG_MODE_INVALID",{value:mode},null,{validationError:true})}let rawAPI;if(mode==="eager"){rawAPI=await this.slothlet.modes.eager.buildAPI({dir,apiPathPrefix,collisionContext,moduleID,apiDepth:this.slothlet.config.apiDepth,cacheBust,fileFilter})}else{rawAPI=await this.slothlet.modes.lazy.buildAPI({dir,apiPathPrefix,collisionContext,collisionMode,moduleID,apiDepth:this.slothlet.config.apiDepth,cacheBust,fileFilter})}return rawAPI}}export{Builder};
17
+ import{ComponentBase}from"@cldmv/slothlet/factories/component-base";class Builder extends ComponentBase{static slothletProperty="builder";constructor(slothlet){super(slothlet)}async buildAPI(options){const{dir,mode="eager",apiPathPrefix="",collisionContext="initial",moduleID,cacheBust=null,fileFilter=null,hidden=null,scanHiddenFolders=false,collisionMode=null,syntheticExports=null,syntheticName="synthetic"}=options;let preloadedStructure=null;let effectiveDir=dir;if(syntheticExports!=null){const isPlainObject=value=>{if(value===null||typeof value!=="object")return false;const proto=Object.getPrototypeOf(value);return proto===Object.prototype||proto===null};if(!isPlainObject(syntheticExports)){throw new this.SlothletError("INVALID_CONFIG_SYNTHETIC_EXPORTS_SHAPE",{received:Array.isArray(syntheticExports)?"array":typeof syntheticExports==="object"?`${syntheticExports.constructor?.name??"non-plain object"} instance`:typeof syntheticExports,validationError:true})}if(typeof syntheticName!=="string"||!syntheticName){throw new this.SlothletError("INVALID_CONFIG_SYNTHETIC_NAME",{received:typeof syntheticName==="string"?"<empty>":typeof syntheticName,validationError:true})}const sentinel=`synthetic:${syntheticName}`;effectiveDir=sentinel;preloadedStructure={files:[{path:sentinel,name:syntheticName,fullName:`${syntheticName}.mjs`,moduleID,synthetic:true,exports:syntheticExports}],directories:[]}}else if(!dir||typeof dir!=="string"){throw new this.SlothletError("INVALID_CONFIG_DIR_INVALID",{dir},null,{validationError:true})}if(mode!=="eager"&&mode!=="lazy"){throw new this.SlothletError("INVALID_CONFIG_MODE_INVALID",{value:mode},null,{validationError:true})}let rawAPI;if(mode==="eager"){rawAPI=await this.slothlet.modes.eager.buildAPI({dir:effectiveDir,apiPathPrefix,collisionContext,moduleID,apiDepth:this.slothlet.config.apiDepth,cacheBust,fileFilter,hidden,scanHiddenFolders,preloadedStructure})}else{rawAPI=await this.slothlet.modes.lazy.buildAPI({dir:effectiveDir,apiPathPrefix,collisionContext,collisionMode,moduleID,apiDepth:this.slothlet.config.apiDepth,cacheBust,fileFilter,hidden,scanHiddenFolders,preloadedStructure})}return rawAPI}}export{Builder};
@@ -14,4 +14,4 @@
14
14
  limitations under the License.
15
15
  */
16
16
 
17
- import{ComponentBase}from"@cldmv/slothlet/factories/component-base";import{t}from"@cldmv/slothlet/i18n";import{UnifiedWrapper,resolveWrapper}from"@cldmv/slothlet/handlers/unified-wrapper";import{getInstanceToken}from"@cldmv/slothlet/handlers/lifecycle-token";class ModesProcessor extends ComponentBase{static slothletProperty="modesProcessor";constructor(slothlet){super(slothlet)}async processFiles(api,files,directory,currentDepth,mode,isRoot,recursive,populateDirectly=false,apiPathPrefix="",collisionContext="initial",moduleID=null,sourceFolder=null,cacheBust=null,collisionModeOverride=null){const buildApiPath=path=>{if(!apiPathPrefix)return path;if(path.startsWith(`${apiPathPrefix}.`)){return path}return`${apiPathPrefix}.${path}`};let rootDefaultFunction=null;const rootContributors=[];const categoryName=isRoot&&!populateDirectly?null:this.slothlet.helpers.sanitize.sanitizePropertyName(directory.name);let targetApi=isRoot&&!populateDirectly?api:populateDirectly?api:api[categoryName]=api[categoryName]||{};const isRootFile=currentDepth===0&&!populateDirectly;const effectiveMode=mode==="lazy"&&isRootFile?"eager":mode;const shouldWrap=!(effectiveMode==="lazy"&&populateDirectly);if(!isRoot&&shouldWrap&&!populateDirectly){const existingTarget=api[categoryName];if(existingTarget&&resolveWrapper(existingTarget)){if(this.slothlet.config.debug?.modes){this.slothlet.debug("modes",{key:"DEBUG_MODE_CATEGORY_REUSE_EXISTING_WRAPPER",categoryName,apiPath:resolveWrapper(existingTarget)?.apiPath})}targetApi=existingTarget}else if(existingTarget===void 0||typeof existingTarget==="object"&&existingTarget!==null){const initialImpl=resolveWrapper(existingTarget)?{}:this.slothlet.helpers.modesUtils.cloneWrapperImpl(existingTarget||{},mode);if(this.slothlet.config.debug?.modes){this.slothlet.debug("modes",{key:"DEBUG_MODE_CATEGORY_WRAPPER_CREATED",categoryName,apiPath:buildApiPath(categoryName)})}const wrapper=new UnifiedWrapper(this.slothlet,{mode:effectiveMode,apiPath:buildApiPath(categoryName),initialImpl,filePath:directory.path,moduleID:moduleID||categoryName,sourceFolder});api[categoryName]=wrapper.createProxy();if(this.slothlet.handlers?.metadata){this.slothlet.handlers.metadata.tagSystemMetadata(wrapper,{filePath:directory.path,apiPath:buildApiPath(categoryName),moduleID:moduleID||"base",sourceFolder:sourceFolder||directory.path},getInstanceToken(this.slothlet))}if(this.slothlet.config.debug?.modes){this.slothlet.debug("modes",{key:"DEBUG_MODE_CATEGORY_WRAPPER_ASSIGNED",categoryName})}targetApi=api[categoryName];if(this.slothlet.config.debug?.modes){this.slothlet.debug("modes",{key:"DEBUG_MODE_CATEGORY_CREATED",categoryName,apiPath:wrapper.apiPath});this.slothlet.debug("modes",{key:"DEBUG_MODE_CATEGORY_TARGET_API_STATUS",isWrapper:!!resolveWrapper(targetApi),targetApiKeys:Object.keys(targetApi)})}}}if(!isRoot&&this.slothlet.config.debug?.modes){this.slothlet.debug("modes",{message:await t("DEBUG_MODE_PROCESSING_DIRECTORY",{mode,categoryName,currentDepth})})}const loadedModules=[];for(const file of files){if(this.slothlet.config.debug?.modes&&categoryName==="string"){this.slothlet.debug("modes",{key:"DEBUG_MODE_PROCESSING_FILE",categoryName,file:file.name,isRoot,populateDirectly,mode})}try{const mod=await this.slothlet.processors.loader.loadModule(file.path,this.slothlet.instanceID,moduleID,cacheBust);const exports=this.slothlet.processors.loader.extractExports(mod);const moduleName=this.slothlet.helpers.sanitize.sanitizePropertyName(file.name);const moduleKeys=Object.keys(exports).filter(k=>k!=="default");const analysis={hasDefault:exports.default!==void 0,hasNamed:moduleKeys.length>0,defaultExportType:exports.default?typeof exports.default:null};loadedModules.push({file,mod:exports,moduleName,moduleKeys,analysis})}catch(error){if(error.name==="SlothletError")throw error;throw new this.SlothletError("MODULE_LOAD_FAILED",{modulePath:file.path,moduleID:moduleID||file.moduleID},error)}}const hasMultipleDefaults=loadedModules.filter(m=>m.analysis.hasDefault).length>1;for(const{file,mod,moduleName,moduleKeys,analysis}of loadedModules){if(this.slothlet.config.debug?.modes&&categoryName==="logger"){this.slothlet.debug("modes",{key:"DEBUG_MODE_PROCESSING_MODULE",categoryName,moduleName,hasDefault:analysis.hasDefault,moduleKeys,targetApiType:typeof targetApi,targetApiCallable:typeof targetApi==="function"})}const isAddapiFile=moduleName==="addapi"||file.name==="addapi"||file.fullName&&["addapi.mjs","addapi.cjs","addapi.js","addapi.ts"].includes(file.fullName.toLowerCase());const isAddapiObjectDefault=isAddapiFile&&analysis.hasDefault&&typeof mod.default!=="function";const isRootContributor=isRoot&&analysis.hasDefault&&typeof mod.default==="function"&&!isAddapiObjectDefault;if(moduleName==="config"||moduleKeys.some(k=>k.includes("Config")||k.includes("config"))){if(this.slothlet.config.debug?.modes){this.slothlet.debug("modes",{key:"DEBUG_MODE_FILE_PROCESSING",module:moduleName,category:categoryName||"(none)",isRoot,hasDefault:analysis.hasDefault,moduleKeys})}}if(isRootContributor){const defaultFunc=this.slothlet.helpers.modesUtils.ensureNamedExportFunction(mod.default,moduleName);for(const key of moduleKeys){if(!this.slothlet.processors.flatten.shouldAttachNamedExport(key,mod[key],defaultFunc,mod.default)){continue}defaultFunc[key]=mod[key]}rootContributors.push({moduleName,file,defaultFunc});continue}else{const decision=await this.slothlet.processors.flatten.getFlatteningDecision({mod,moduleName,categoryName:categoryName||moduleName,analysis,hasMultipleDefaults,moduleKeys,t});if(this.slothlet.config.debug?.modes){this.slothlet.debug("modes",{message:await t("DEBUG_MODE_MODULE_DECISION",{mode,moduleName,reason:decision.reason})})}const propertyName=decision.preferredName||moduleName;const effectiveCategoryName=categoryName||moduleName;let{moduleContent}=this.slothlet.processors.flatten.processModuleForAPI({mod,decision,moduleName,propertyName,moduleKeys,analysis,file,collisionContext,apiPathPrefix:apiPathPrefix||""});if(!isRoot&&!apiPathPrefix&&moduleName===categoryName){if(moduleKeys.length===1&&moduleKeys[0]===moduleName&&!analysis.hasDefault){const exportedValue=mod[moduleName];if(typeof exportedValue==="object"&&exportedValue!==null){if(this.slothlet.config.debug?.modes&&categoryName==="string"){this.slothlet.debug("modes",{key:"DEBUG_MODE_SINGLE_FILE_FOLDER_DETECTED",categoryName,populateDirectly,isRoot,mode,exportKeys:Object.keys(exportedValue)})}if(shouldWrap){const wrapper=new UnifiedWrapper(this.slothlet,{mode:effectiveMode,apiPath:buildApiPath(categoryName),initialImpl:exportedValue,materializeOnCreate:this.slothlet.config.backgroundMaterialize,filePath:file.path,moduleID:moduleID||file.moduleID,sourceFolder});api[categoryName]=wrapper.createProxy();targetApi=api[categoryName]}else{this.slothlet.debug("modes",{key:"DEBUG_MODE_SINGLE_FILE_FOLDER_WRAPPED",categoryName,implKeys:Object.keys(exportedValue)})}for(const key of Object.keys(exportedValue)){if(this.slothlet.handlers.ownership){this.slothlet.handlers.ownership.register({moduleID:moduleID||file.moduleID,apiPath:`${categoryName}.${key}`,source:"core",collisionMode:this.slothlet.helpers.modesUtils.getOwnershipCollisionMode(this.slothlet.config,collisionContext),filePath:file.path})}}continue}}else if(analysis.hasDefault){const namedKeys=moduleKeys.length>0?moduleKeys:Object.keys(mod).filter(key=>key!=="default");const callableModule=typeof mod.default==="function"?this.slothlet.helpers.modesUtils.ensureNamedExportFunction(mod.default,categoryName):moduleContent;if(namedKeys.length>0){for(const key of namedKeys){if(key in callableModule){continue}if(!this.slothlet.processors.flatten.shouldAttachNamedExport(key,mod[key],callableModule,mod.default)){continue}callableModule[key]=mod[key]}}moduleContent=callableModule;if(shouldWrap){const wrapper=new UnifiedWrapper(this.slothlet,{mode:effectiveMode,apiPath:buildApiPath(categoryName),initialImpl:this.slothlet.helpers.modesUtils.cloneWrapperImpl(callableModule,mode),materializeOnCreate:this.slothlet.config.backgroundMaterialize,filePath:file.path,moduleID:moduleID||file.moduleID,sourceFolder});api[categoryName]=wrapper.createProxy();targetApi=api[categoryName]}else{api[categoryName]=moduleContent;targetApi=api[categoryName]}const needsSeparateNamedExports=typeof mod.default==="function";if(needsSeparateNamedExports&&namedKeys.length>0){for(const key of namedKeys){if(shouldWrap){const namedWrapper=new UnifiedWrapper(this.slothlet,{mode:effectiveMode,apiPath:buildApiPath(`${categoryName}.${key}`),initialImpl:mod[key],materializeOnCreate:this.slothlet.config.backgroundMaterialize,filePath:file.path,moduleID:moduleID||file.moduleID,sourceFolder});this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,key,namedWrapper.createProxy(),{useCollisionDetection:true,config:this.slothlet.config,collisionContext})}else{this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,key,mod[key],{useCollisionDetection:true,config:this.slothlet.config,collisionContext})}if(this.slothlet.handlers.ownership){this.slothlet.handlers.ownership.register({moduleID:moduleID||file.moduleID,apiPath:`${categoryName}.${key}`,source:"core",collisionMode:this.slothlet.helpers.modesUtils.getOwnershipCollisionMode(this.slothlet.config,collisionContext),filePath:file.path})}}}if(this.slothlet.handlers.ownership){this.slothlet.handlers.ownership.register({moduleID:moduleID||file.moduleID,apiPath:categoryName,source:"core",collisionMode:this.slothlet.helpers.modesUtils.getOwnershipCollisionMode(this.slothlet.config,collisionContext),filePath:file.path})}continue}else if(moduleKeys.length>0){const hasMatchingObject=moduleKeys.some(key=>key===moduleName&&typeof mod[key]==="object"&&mod[key]!==null&&!Array.isArray(mod[key]));if(hasMatchingObject){const matchingObj=mod[moduleName];for(const[propKey,propValue]of Object.entries(matchingObj)){if(shouldWrap){const wrapper=new UnifiedWrapper(this.slothlet,{mode:effectiveMode,apiPath:buildApiPath(`${categoryName}.${propKey}`),initialImpl:this.slothlet.helpers.modesUtils.cloneWrapperImpl(propValue,mode),materializeOnCreate:this.slothlet.config.backgroundMaterialize,filePath:file.path,moduleID:moduleID||file.moduleID,sourceFolder});this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,propKey,wrapper.createProxy(),{useCollisionDetection:true,config:this.slothlet.config,collisionContext})}else{this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,propKey,propValue,{useCollisionDetection:true,config:this.slothlet.config,collisionContext})}if(this.slothlet.handlers.ownership){this.slothlet.handlers.ownership.register({moduleID:moduleID||file.moduleID,apiPath:`${categoryName}.${propKey}`,source:"core",collisionMode:this.slothlet.helpers.modesUtils.getOwnershipCollisionMode(this.slothlet.config,collisionContext),filePath:file.path})}}for(const key of moduleKeys){if(key!==moduleName){if(shouldWrap){const wrapper=new UnifiedWrapper(this.slothlet,{mode:effectiveMode,apiPath:buildApiPath(`${categoryName}.${key}`),initialImpl:this.slothlet.helpers.modesUtils.cloneWrapperImpl(mod[key],mode),materializeOnCreate:this.slothlet.config.backgroundMaterialize,filePath:file.path,moduleID:moduleID||file.moduleID,sourceFolder});this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,key,wrapper.createProxy(),{useCollisionDetection:true,config:this.slothlet.config,collisionContext})}else{this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,key,mod[key],{useCollisionDetection:true,config:this.slothlet.config,collisionContext})}if(this.slothlet.handlers.ownership){this.slothlet.handlers.ownership.register({moduleID:moduleID||file.moduleID,apiPath:`${categoryName}.${key}`,source:"core",collisionMode:this.slothlet.helpers.modesUtils.getOwnershipCollisionMode(this.slothlet.config,collisionContext),filePath:file.path})}}}}else{if(this.slothlet.config.debug?.modes){this.slothlet.debug("modes",{key:"DEBUG_MODE_FLATTEN_MULTI_EXPORT_FILE",moduleName,categoryName,exportCount:moduleKeys.length});this.slothlet.debug("modes",{key:"DEBUG_MODE_FLATTEN_MULTI_EXPORT_TARGET_STATUS",isWrapper:!!resolveWrapper(targetApi),keysBefore:Object.keys(targetApi)})}for(const key of moduleKeys){if(this.slothlet.config.debug?.modes){this.slothlet.debug("modes",{key:"DEBUG_MODE_FLATTEN_MULTI_EXPORT_ASSIGNING",propKey:key})}if(shouldWrap){const wrapper=new UnifiedWrapper(this.slothlet,{mode:effectiveMode,apiPath:buildApiPath(`${categoryName}.${key}`),initialImpl:this.slothlet.helpers.modesUtils.cloneWrapperImpl(mod[key],mode),materializeOnCreate:this.slothlet.config.backgroundMaterialize,filePath:file.path,moduleID:moduleID||file.moduleID,sourceFolder});const assigned=this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,key,wrapper.createProxy(),{useCollisionDetection:true,config:this.slothlet.config,collisionContext});if(assigned){this.slothlet.debug("modes",{key:"DEBUG_MODE_FLATTEN_MULTI_EXPORT_ASSIGNED",propKey:key,keysAfter:Object.keys(targetApi)})}else{this.slothlet.debug("modes",{key:"DEBUG_MODE_FLATTEN_MULTI_EXPORT_BLOCKED",propKey:key})}}else{this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,key,mod[key],{useCollisionDetection:true,config:this.slothlet.config,collisionContext})}if(this.slothlet.handlers.ownership){this.slothlet.handlers.ownership.register({moduleID:moduleID||file.moduleID,apiPath:`${categoryName}.${key}`,source:"core",collisionMode:this.slothlet.helpers.modesUtils.getOwnershipCollisionMode(this.slothlet.config,collisionContext),filePath:file.path})}}}continue}}if(!analysis.hasDefault&&moduleKeys.length===1&&!isRoot){const key=moduleKeys[0];const keyValue=mod[key];const isMatchingObject=key===moduleName&&typeof keyValue==="object"&&keyValue!==null&&!Array.isArray(keyValue);if(!isMatchingObject){const normalizedKey=key.toLowerCase().replace(/[-_]/g,"");const normalizedModuleName=moduleName.toLowerCase().replace(/[-_]/g,"");if(normalizedKey===normalizedModuleName){const preferredName=key;if(shouldWrap){const wrapper=new UnifiedWrapper(this.slothlet,{mode:effectiveMode,apiPath:buildApiPath(`${categoryName}.${preferredName}`),initialImpl:this.slothlet.helpers.modesUtils.cloneWrapperImpl(mod[key],mode),materializeOnCreate:this.slothlet.config.backgroundMaterialize,filePath:file.path,moduleID:moduleID||file.moduleID,sourceFolder});this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,preferredName,wrapper.createProxy(),{useCollisionDetection:true,config:this.slothlet.config,collisionContext})}else{this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,preferredName,mod[key],{useCollisionDetection:true,config:this.slothlet.config,collisionContext})}if(this.slothlet.handlers.ownership){this.slothlet.handlers.ownership.register({moduleID:moduleID||file.moduleID,apiPath:`${categoryName}.${preferredName}`,source:"core",collisionMode:this.slothlet.helpers.modesUtils.getOwnershipCollisionMode(this.slothlet.config,collisionContext),filePath:file.path})}continue}}}if(decision.flattenToRoot&&moduleContent&&!isRoot&&!this.slothlet.config.suppressFixes?.has("C03_116")){for(const key of Object.keys(moduleContent)){const value=moduleContent[key];const keyPath=apiPathPrefix?`${apiPathPrefix}.${key}`:`${categoryName}.${key}`;if(shouldWrap&&typeof value==="function"){const wrapper=new UnifiedWrapper(this.slothlet,{mode:effectiveMode,apiPath:buildApiPath(keyPath),initialImpl:value,materializeOnCreate:this.slothlet.config.backgroundMaterialize,filePath:file.path,moduleID:moduleID||file.moduleID,sourceFolder});this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,key,wrapper.createProxy(),{useCollisionDetection:true,config:this.slothlet.config,collisionContext})}else{this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,key,value,{useCollisionDetection:true,config:this.slothlet.config,collisionContext})}}if(this.slothlet.handlers.ownership){for(const key of Object.keys(moduleContent)){const apiPath=apiPathPrefix?`${apiPathPrefix}.${key}`:`${categoryName}.${key}`;this.slothlet.handlers.ownership.register({moduleID:moduleID||file.moduleID,apiPath,source:"core",collisionMode:this.slothlet.helpers.modesUtils.getOwnershipCollisionMode(this.slothlet.config,collisionContext),filePath:file.path})}}continue}if(decision.flattenToCategory&&moduleContent&&effectiveCategoryName){const isAddapiFile2=decision.flattenType==="addapi-metadata-default"||decision.flattenType==="addapi-special-file";if(isAddapiFile2&&typeof moduleContent==="object"&&!Array.isArray(moduleContent)&&typeof moduleContent!=="function"){for(const key of Object.keys(moduleContent)){const value=moduleContent[key];const keyPath=isRoot?key:`${apiPathPrefix?apiPathPrefix+".":""}${key}`;if(shouldWrap&&typeof value==="function"){const wrapper=new UnifiedWrapper(this.slothlet,{mode:effectiveMode,apiPath:buildApiPath(keyPath),initialImpl:value,materializeOnCreate:this.slothlet.config.backgroundMaterialize,filePath:file.path,moduleID:moduleID||file.moduleID,sourceFolder});this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,key,wrapper.createProxy(),{useCollisionDetection:true,config:this.slothlet.config,collisionContext})}else{this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,key,value,{useCollisionDetection:true,config:this.slothlet.config,collisionContext})}}if(this.slothlet.handlers.ownership){for(const key of Object.keys(moduleContent)){const apiPath=isRoot?key:apiPathPrefix?`${apiPathPrefix}.${key}`:key;this.slothlet.handlers.ownership.register({moduleID:moduleID||file.moduleID,apiPath,source:"core",collisionMode:this.slothlet.helpers.modesUtils.getOwnershipCollisionMode(this.slothlet.config,collisionContext),config:this.slothlet.config})}}}else{const localPath=isRoot?effectiveCategoryName:`${apiPathPrefix?apiPathPrefix+".":""}${effectiveCategoryName}`;if(shouldWrap){const wrapper=new UnifiedWrapper(this.slothlet,{mode:effectiveMode,apiPath:buildApiPath(localPath),initialImpl:moduleContent,materializeOnCreate:this.slothlet.config.backgroundMaterialize,filePath:file.path,moduleID:moduleID||file.moduleID,sourceFolder,isCallable:typeof moduleContent==="function"});this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,effectiveCategoryName,wrapper.createProxy(),{useCollisionDetection:true,config:this.slothlet.config,collisionContext})}else{this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,effectiveCategoryName,moduleContent,{useCollisionDetection:true,config:this.slothlet.config,collisionContext})}if(this.slothlet.handlers.ownership){const apiPath=isRoot?effectiveCategoryName:apiPathPrefix?`${apiPathPrefix}.${effectiveCategoryName}`:effectiveCategoryName;this.slothlet.handlers.ownership.register({moduleID:moduleID||file.moduleID,apiPath,source:"core",collisionMode:this.slothlet.helpers.modesUtils.getOwnershipCollisionMode(this.slothlet.config,collisionContext),config:this.slothlet.config})}}continue}if(shouldWrap){const localPath=isRoot?propertyName:`${categoryName}.${propertyName}`;const wrapper=new UnifiedWrapper(this.slothlet,{mode:effectiveMode,apiPath:buildApiPath(localPath),initialImpl:moduleContent,materializeOnCreate:this.slothlet.config.backgroundMaterialize,filePath:file.path,moduleID:moduleID||file.moduleID,sourceFolder});this.slothlet.debug("modes",{key:"DEBUG_MODE_FILE_WRAPPER_ASSIGNMENT",propertyName,apiPath:buildApiPath(localPath),overwriting:propertyName in targetApi?resolveWrapper(targetApi[propertyName])?"wrapper":"value":"nothing"});this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,propertyName,wrapper.createProxy(),{useCollisionDetection:true,config:this.slothlet.config,collisionContext})}else{this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,propertyName,moduleContent,{useCollisionDetection:true,config:this.slothlet.config,collisionContext})}if(this.slothlet.config.debug?.modes&&categoryName==="logger"){this.slothlet.debug("modes",{key:"DEBUG_MODE_AFTER_ASSIGNMENT_STATUS",targetApiType:typeof targetApi,propertyName,hasProperty:propertyName in targetApi,implType:typeof resolveWrapper(targetApi)?.____slothletInternal.impl,implHasProperty:!!resolveWrapper(targetApi)?.____slothletInternal.impl?.utils})}if(this.slothlet.handlers.ownership){const apiPath=isRoot?propertyName:`${categoryName}.${propertyName}`;this.slothlet.handlers.ownership.register({moduleID:moduleID||file.moduleID,apiPath,source:"core",collisionMode:this.slothlet.helpers.modesUtils.getOwnershipCollisionMode(this.slothlet.config,collisionContext),config:this.slothlet.config})}}}if(this.slothlet.config.debug?.modes){this.slothlet.debug("modes",{key:"DEBUG_MODE_SUBDIRECTORY_CHECK",isRoot,categoryName,hasDirectory:!!directory,hasChildren:!!directory?.children,directoryCount:directory?.children?.directories?.length||0})}this.slothlet.debug("modes",{key:"DEBUG_MODE_DIRECTORY_CHECK",hasChildren:!!directory?.children,hasDirectories:!!directory?.children?.directories,length:directory?.children?.directories?.length||0});if(directory?.children?.directories){this.slothlet.debug("modes",{key:"DEBUG_MODE_DIRECTORY_CHECK_PASSED",recursive});if(this.slothlet.config.debug?.modes){this.slothlet.debug("modes",{key:"DEBUG_MODE_SUBDIRECTORIES_FOUND",subdirectoryCount:directory.children.directories.length,recursive})}if(recursive){this.slothlet.debug("modes",{key:"DEBUG_MODE_SUBDIRECTORY_LOOP_START",count:directory.children.directories.length});for(const subDir of directory.children.directories){this.slothlet.debug("modes",{key:"DEBUG_MODE_PROCESSING_SUBDIRECTORY",name:subDir.name,fileCount:subDir.children.files.length,subdirCount:subDir.children.directories.length});const subDirName=this.slothlet.helpers.sanitize.sanitizePropertyName(subDir.name);if(subDir.children.files.length===1&&subDir.children.directories.length===0){const file=subDir.children.files[0];const moduleName=this.slothlet.helpers.sanitize.sanitizePropertyName(file.name);const genericFilenames=["singlefile","index","main","default"];const isGeneric=genericFilenames.includes(moduleName.toLowerCase());const filenameMatchesFolder=moduleName===subDirName;if(isGeneric||filenameMatchesFolder){this.slothlet.debug("modes",{key:"DEBUG_MODE_FOLDER_LEVEL_FLATTEN_CHECK",subDir:subDirName,file:moduleName,isGeneric,filenameMatches:filenameMatchesFolder});const mod=await this.slothlet.processors.loader.loadModule(file.path,this.slothlet.instanceID,moduleID,cacheBust);const exports=this.slothlet.processors.loader.extractExports(mod);const moduleKeys=Object.keys(exports).filter(k=>k!=="default");const analysis={hasDefault:exports.default!==void 0,hasNamed:moduleKeys.length>0,defaultExportType:exports.default?typeof exports.default:null};const modContent=exports.default!==void 0?exports.default:exports;const categoryDecision=await this.slothlet.processors.flatten.buildCategoryDecisions({categoryName:subDirName,mod:modContent,moduleName,fileBaseName:file.name,analysis,moduleKeys,currentDepth:currentDepth+1,moduleFiles:subDir.children.files,t});if(categoryDecision.shouldFlatten){this.slothlet.debug("modes",{key:"DEBUG_MODE_FOLDER_LEVEL_FLATTEN_SKIP_RECURSION",subDir:subDirName});let implToWrap;if(categoryDecision.flattenType==="addapi-metadata-default"){implToWrap={};for(const key of moduleKeys){if(key!=="default"){implToWrap[key]=exports[key]}}}else if(moduleName===subDirName&&moduleKeys.includes(subDirName)){implToWrap=exports[subDirName]}else if(exports.default!==void 0){implToWrap=exports.default;if(moduleKeys.length>0){if(typeof implToWrap==="function"){const collisionConfig=this.slothlet.config.api?.collision||this.slothlet.config.collision;const collisionMode=(collisionContext==="initial"?collisionConfig?.initial:collisionConfig?.api)||"merge";for(const key of moduleKeys){if(key!=="default"){const hasExisting=implToWrap[key]!==void 0;if(hasExisting){if(collisionMode==="merge"||collisionMode==="skip"){continue}else if(collisionMode==="error"){throw new this.slothlet.SlothletError("COLLISION_DEFAULT_EXPORT_ERROR",{key,apiPath:`${apiPathPrefix}.${subDirName}`},null,{validationError:true})}else if(collisionMode==="warn"){new this.slothlet.SlothletWarning("WARNING_COLLISION_DEFAULT_EXPORT_OVERWRITE",{key,apiPath:`${apiPathPrefix}.${subDirName}`})}}implToWrap[key]=exports[key]}}}else if(typeof implToWrap==="object"&&implToWrap!==null){for(const key of moduleKeys){if(key!=="default"&&!(key in implToWrap)){implToWrap[key]=exports[key]}}}}}else{implToWrap=modContent}const modes_eagerCollisionConfig=this.slothlet.config.api?.collision||this.slothlet.config.collision;const modes_eagerCollisionMode=(collisionContext==="initial"?modes_eagerCollisionConfig?.initial:modes_eagerCollisionConfig?.api)||"merge";const modes_existingAtKey=targetApi[subDirName];if(modes_existingAtKey!==void 0&&modes_eagerCollisionMode!=="replace"&&modes_eagerCollisionMode!=="skip"){const modes_existingWrapper=resolveWrapper(modes_existingAtKey);if(modes_existingWrapper){if(modes_existingWrapper.____slothletInternal?.materializeFunc&&!modes_existingWrapper.____slothletInternal?.state?.materialized){await modes_existingWrapper._materialize()}if(modes_existingWrapper.____slothletInternal?.impl&&!modes_existingWrapper.____slothletInternal?.state?.childrenAdopted){modes_existingWrapper.___adoptImplChildren()}const modes_existingImpl=modes_existingWrapper.__impl;if(modes_existingImpl&&typeof modes_existingImpl==="object"&&!Array.isArray(modes_existingImpl)){if(typeof implToWrap==="object"&&implToWrap!==null){for(const[k,v]of Object.entries(modes_existingImpl)){if(!(k in implToWrap)){implToWrap[k]=v}}}else if(typeof implToWrap==="function"){for(const[k,v]of Object.entries(modes_existingImpl)){if(implToWrap[k]===void 0){implToWrap[k]=v}}}}const modes_existingChildKeys=Object.keys(modes_existingWrapper).filter(k=>!k.startsWith("_")&&!k.startsWith("__"));for(const ck of modes_existingChildKeys){if(typeof implToWrap==="object"&&implToWrap!==null&&!(ck in implToWrap)){implToWrap[ck]=modes_existingWrapper[ck]}else if(typeof implToWrap==="function"&&implToWrap[ck]===void 0){implToWrap[ck]=modes_existingWrapper[ck]}}this.slothlet.debug("modes",{key:"DEBUG_MODE_FILE_FOLDER_COLLISION_MERGED",subDir:subDirName,mergedKeys:Object.keys(implToWrap)})}}const wrapper=new UnifiedWrapper(this.slothlet,{mode:effectiveMode,apiPath:buildApiPath(categoryName?`${categoryName}.${subDirName}`:subDirName),initialImpl:implToWrap,materializeOnCreate:this.slothlet.config.backgroundMaterialize,filePath:file.path,moduleID:moduleID||file.moduleID,sourceFolder});this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,subDirName,wrapper.createProxy(),{useCollisionDetection:true,config:this.slothlet.config,collisionContext});if(this.slothlet.handlers.ownership){const apiPath=buildApiPath(categoryName?`${categoryName}.${subDirName}`:subDirName);this.slothlet.handlers.ownership.register({moduleID:moduleID||file.moduleID,apiPath,source:"core",collisionMode:this.slothlet.helpers.modesUtils.getOwnershipCollisionMode(this.slothlet.config,collisionContext),config:this.slothlet.config})}continue}}}const currentCategoryName=apiPathPrefix?apiPathPrefix.split(".").pop():categoryName;if(subDirName===currentCategoryName&&currentCategoryName!==null){await this.processFiles(targetApi,subDir.children.files,subDir,currentDepth+1,mode,false,recursive,true,apiPathPrefix,collisionContext,moduleID,sourceFolder,cacheBust);continue}await this.processFiles(targetApi,subDir.children.files,{name:subDirName,path:subDir.path,children:subDir.children},currentDepth+1,mode,false,recursive,false,apiPathPrefix,collisionContext,moduleID,sourceFolder,cacheBust)}}else{for(const subDir of directory.children.directories){const subDirName=this.slothlet.helpers.sanitize.sanitizePropertyName(subDir.name);const lazy_currentCategoryName=apiPathPrefix?apiPathPrefix.split(".").pop():categoryName;if(subDirName===lazy_currentCategoryName&&lazy_currentCategoryName!==null&&!populateDirectly){await this.processFiles(targetApi,subDir.children.files,subDir,currentDepth+1,"eager",false,true,true,apiPathPrefix,collisionContext,moduleID,sourceFolder,cacheBust);continue}const apiPath=categoryName?`${categoryName}.${subDirName}`:apiPathPrefix?`${apiPathPrefix}.${subDirName}`:subDirName;if(this.slothlet.config.debug?.modes){this.slothlet.debug("modes",{key:"DEBUG_MODE_CREATING_LAZY_SUBDIRECTORY",apiPath,fileCount:subDir.children.files.length})}const collisionConfig=this.slothlet.config.api?.collision;const modes_initialCollisionMode=collisionModeOverride||(collisionContext==="initial"?collisionConfig?.initial:collisionConfig?.api)||"replace";let modes_fileFolderImpl=null;const modes_lazyExisting=targetApi[subDirName];if(modes_initialCollisionMode!=="replace"&&resolveWrapper(modes_lazyExisting)){const modes_lazyExistingW=resolveWrapper(modes_lazyExisting);const existImpl=modes_lazyExistingW.__impl;if(existImpl&&typeof existImpl==="object"&&!Array.isArray(existImpl)){modes_fileFolderImpl={...existImpl}}const existChildKeys=Object.keys(modes_lazyExistingW).filter(k=>!k.startsWith("_")&&!k.startsWith("__"));for(const ck of existChildKeys){if(!modes_fileFolderImpl)modes_fileFolderImpl={};if(!(ck in modes_fileFolderImpl)){modes_fileFolderImpl[ck]=modes_lazyExistingW[ck]}}}this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,subDirName,this.createLazySubdirectoryWrapper(subDir,apiPath,moduleID,sourceFolder,cacheBust,modes_fileFolderImpl,modes_initialCollisionMode),{useCollisionDetection:true,config:this.slothlet.config,collisionContext})}}}if(isRoot&&rootContributors.length>0){if(rootContributors.length===1){const{moduleName,file,defaultFunc}=rootContributors[0];rootDefaultFunction=defaultFunc;if(this.slothlet.config.debug?.modes){this.slothlet.debug("modes",{message:await t("DEBUG_MODE_ROOT_CONTRIBUTOR",{mode,functionName:defaultFunc.name||"anonymous"})})}if(this.slothlet.handlers.ownership){this.slothlet.handlers.ownership.register({moduleID:moduleID||file.moduleID,apiPath:moduleName,source:"core",collisionMode:this.slothlet.helpers.modesUtils.getOwnershipCollisionMode(this.slothlet.config,collisionContext),filePath:file.path})}}else{new this.SlothletWarning("WARNING_MULTIPLE_ROOT_CONTRIBUTORS",{rootContributors:rootContributors.map(rc=>rc.moduleName).join(", "),firstContributor:rootContributors[0].moduleName});for(const{moduleName,file,defaultFunc}of rootContributors){if(shouldWrap){const wrapper=new UnifiedWrapper(this.slothlet,{mode:effectiveMode,apiPath:buildApiPath(moduleName),initialImpl:this.slothlet.helpers.modesUtils.cloneWrapperImpl(defaultFunc,mode),materializeOnCreate:this.slothlet.config.backgroundMaterialize,filePath:file.path,moduleID:moduleID||file.moduleID,sourceFolder});this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,moduleName,wrapper.createProxy(),{useCollisionDetection:true,config:this.slothlet.config,collisionContext})}else{this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,moduleName,defaultFunc,{useCollisionDetection:true,config:this.slothlet.config,collisionContext})}if(this.slothlet.handlers.ownership){this.slothlet.handlers.ownership.register({moduleID:moduleID||file.moduleID,apiPath:moduleName,source:"core",collisionMode:this.slothlet.helpers.modesUtils.getOwnershipCollisionMode(this.slothlet.config,collisionContext),filePath:file.path})}}}}return rootDefaultFunction}createLazySubdirectoryWrapper(dir,apiPath,moduleID=null,sourceFolder=null,cacheBust=null,fileFolderCollisionImpl=null,collisionMode="merge"){const lazy_materializeFunc=this.slothlet.modes.lazy.createNamedMaterializeFunc(apiPath,async()=>{if(this.slothlet.config.debug?.modes){this.slothlet.debug("modes",{key:"DEBUG_MODE_MATERIALIZE_FUNCTION_STARTING",dir:dir.name,fileCount:dir.children.files?.length||0})}const categoryName=this.slothlet.helpers.sanitize.sanitizePropertyName(dir.name);const materialized={};const actualSourceFolder=sourceFolder?`${sourceFolder}/${dir.name}`.replace(/\\/g,"/"):`${this.slothlet.config?.dir}/${dir.name}`.replace(/\\/g,"/");const parentPrefix=apiPath.includes(".")?apiPath.split(".").slice(0,-1).join("."):"";const subDirs=dir.children.directories||[];if(dir.children.files.length===1&&subDirs.length===0){const file=dir.children.files[0];const moduleName=this.slothlet.helpers.sanitize.sanitizePropertyName(file.name);const genericFilenames=["singlefile","index","main","default"];const isGeneric=genericFilenames.includes(moduleName.toLowerCase());const filenameMatchesFolder=moduleName===categoryName;if(isGeneric||filenameMatchesFolder){const mod=await this.slothlet.processors.loader.loadModule(file.path,this.slothlet.instanceID,moduleID,cacheBust);const exports=this.slothlet.processors.loader.extractExports(mod);const moduleKeys=Object.keys(exports).filter(k=>k!=="default");const analysis={hasDefault:exports.default!==void 0,hasNamed:moduleKeys.length>0,defaultExportType:exports.default?typeof exports.default:null};const modContent=exports.default!==void 0?exports.default:exports;const categoryDecision=await this.slothlet.processors.flatten.buildCategoryDecisions({categoryName,mod:modContent,moduleName,fileBaseName:file.name,analysis,moduleKeys,currentDepth:apiPath.split(".").length,moduleFiles:dir.children.files,t});if(categoryDecision.shouldFlatten){let implToWrap;if(categoryDecision.flattenType==="addapi-metadata-default"){implToWrap=exports.default;for(const key of moduleKeys){if(key!=="default"){implToWrap[key]=exports[key]}}}else if(moduleName===categoryName&&moduleKeys.includes(categoryName)){implToWrap=exports[categoryName]}else if(exports.default!==void 0){implToWrap=exports.default;if(moduleKeys.length>0&&(typeof implToWrap==="function"||typeof implToWrap==="object"&&implToWrap!==null)){const collisionMode2=this.slothlet.config?.collision?.initial||"merge";for(const key of moduleKeys){if(!this.slothlet.processors.flatten.shouldAttachNamedExport(key,exports[key],implToWrap,exports.default)){continue}const hasExisting=Object.prototype.hasOwnProperty.call(implToWrap,key);if(hasExisting){if(collisionMode2==="merge"||collisionMode2==="skip"){continue}else if(collisionMode2==="error"){throw new this.slothlet.SlothletError("COLLISION_DEFAULT_EXPORT_ERROR",{key,apiPath},null,{validationError:true})}else if(collisionMode2==="warn"){new this.slothlet.SlothletWarning("WARNING_COLLISION_DEFAULT_EXPORT_OVERWRITE",{key,apiPath})}}implToWrap[key]=exports[key]}}}else{implToWrap=modContent}if(implToWrap&&typeof implToWrap==="object"&&this.slothlet.handlers?.lifecycle){for(const key of Object.keys(implToWrap)){const value=implToWrap[key];if(typeof value==="function"){this.slothlet.handlers.lifecycle.emit("impl:created",{apiPath:`${apiPath}.${key}`,impl:value,source:"lazy-materialization",moduleID,filePath:file.path,sourceFolder:sourceFolder||this.slothlet.config?.dir})}}}if(implToWrap&&typeof implToWrap==="object"){const childPaths={};for(const key of Object.keys(implToWrap)){if(typeof key!=="symbol"&&key!=="__childFilePaths"&&key!=="__filePath"){childPaths[key]=file.path}}implToWrap.__childFilePaths=childPaths}if(fileFolderCollisionImpl&&typeof implToWrap==="object"&&implToWrap!==null){for(const[k,v]of Object.entries(fileFolderCollisionImpl)){if(!(k in implToWrap)){implToWrap[k]=v}}}else if(fileFolderCollisionImpl&&typeof implToWrap==="function"){for(const[k,v]of Object.entries(fileFolderCollisionImpl)){if(implToWrap[k]===void 0){implToWrap[k]=v}}}return implToWrap}}}await this.processFiles(materialized,dir.children.files,{name:dir.name,children:dir.children},0,"eager",false,false,true,parentPrefix,"initial",moduleID,actualSourceFolder,cacheBust,collisionMode);if(this.slothlet.config.debug?.modes){this.slothlet.debug("modes",{key:"DEBUG_MODE_MATERIALIZE_FUNCTION_RETURNING_IMPL",dir:dir.name,keys:Object.keys(materialized)})}if(fileFolderCollisionImpl){for(const[k,v]of Object.entries(fileFolderCollisionImpl)){if(!(k in materialized)){materialized[k]=v}}}const materializedKeys=Object.keys(materialized);const _hasCategoryFile=dir.children.files.some(f=>this.slothlet.helpers.sanitize.sanitizePropertyName(f.name)===categoryName);if(_hasCategoryFile&&materializedKeys.includes(categoryName)&&materializedKeys.length>1){if(this.slothlet.config.debug?.modes){this.slothlet.debug("modes",{key:"DEBUG_MODE_FOLDER_PATTERN_MATCH",dir:dir.name,categoryName,keys:materializedKeys})}const mainValue=materialized[categoryName];for(const key of materializedKeys){if(key!==categoryName){if(this.slothlet.config.debug?.modes){this.slothlet.debug("modes",{key:"DEBUG_MODE_FOLDER_PATTERN_ATTACH_PROPERTY",categoryName,propKey:key,valueType:typeof materialized[key]})}mainValue[key]=materialized[key]}}if(this.slothlet.config.debug?.modes){this.slothlet.debug("modes",{key:"DEBUG_MODE_FOLDER_PATTERN_RETURN",categoryName,keys:Object.keys(mainValue).filter(k=>!k.startsWith("__"))})}return mainValue}if(materializedKeys.length===1&&materializedKeys[0]===categoryName){const nestedValue=materialized[categoryName];if(nestedValue&&resolveWrapper(nestedValue)!==null){const attachedKeys=Object.keys(nestedValue).filter(key=>key!=="____slothletInternal");if(attachedKeys.length>0){return nestedValue}return nestedValue.__impl??nestedValue}else{return nestedValue}}return materialized});const wrapper=new UnifiedWrapper(this.slothlet,{mode:"lazy",apiPath,materializeFunc:lazy_materializeFunc,materializeOnCreate:this.slothlet.config.backgroundMaterialize,filePath:dir.path,moduleID,sourceFolder});if(collisionMode){wrapper.____slothletInternal.state.collisionMode=collisionMode}const shouldPrePopulate=collisionMode==="merge"||collisionMode==="warn";if(fileFolderCollisionImpl&&shouldPrePopulate){for(const[k,v]of Object.entries(fileFolderCollisionImpl)){if(typeof k==="string"&&!k.startsWith("_")&&!k.startsWith("__")){Object.defineProperty(wrapper,k,{value:v,writable:false,enumerable:true,configurable:true})}}}return wrapper.createProxy()}async applyRootContributor(api,rootFunction,mode){if(rootFunction){Object.assign(rootFunction,api);if(this.slothlet.config.debug?.modes){this.slothlet.debug("modes",{message:await t("DEBUG_MODE_ROOT_CONTRIBUTOR_APPLIED",{mode,properties:Object.keys(api).length})})}return rootFunction}return api}}export{ModesProcessor};
17
+ import{ComponentBase}from"@cldmv/slothlet/factories/component-base";import{t}from"@cldmv/slothlet/i18n";import{UnifiedWrapper,resolveWrapper}from"@cldmv/slothlet/handlers/unified-wrapper";import{getInstanceToken}from"@cldmv/slothlet/handlers/lifecycle-token";class ModesProcessor extends ComponentBase{static slothletProperty="modesProcessor";constructor(slothlet){super(slothlet)}async processFiles(api,files,directory,currentDepth,mode,isRoot,recursive,populateDirectly=false,apiPathPrefix="",collisionContext="initial",moduleID=null,sourceFolder=null,cacheBust=null,collisionModeOverride=null){const buildApiPath=path=>{if(!apiPathPrefix)return path;if(path.startsWith(`${apiPathPrefix}.`)){return path}return`${apiPathPrefix}.${path}`};let rootDefaultFunction=null;const rootContributors=[];const categoryName=isRoot&&!populateDirectly?null:this.slothlet.helpers.sanitize.sanitizePropertyName(directory.name);let targetApi=isRoot&&!populateDirectly?api:populateDirectly?api:api[categoryName]=api[categoryName]||{};const isRootFile=currentDepth===0&&!populateDirectly;const effectiveMode=mode==="lazy"&&isRootFile?"eager":mode;const shouldWrap=!(effectiveMode==="lazy"&&populateDirectly);if(!isRoot&&shouldWrap&&!populateDirectly){const existingTarget=api[categoryName];if(existingTarget&&resolveWrapper(existingTarget)){if(this.slothlet.config.debug?.modes){this.slothlet.debug("modes",{key:"DEBUG_MODE_CATEGORY_REUSE_EXISTING_WRAPPER",categoryName,apiPath:resolveWrapper(existingTarget)?.apiPath})}targetApi=existingTarget}else if(existingTarget===void 0||typeof existingTarget==="object"&&existingTarget!==null){const initialImpl=resolveWrapper(existingTarget)?{}:this.slothlet.helpers.modesUtils.cloneWrapperImpl(existingTarget||{},mode);if(this.slothlet.config.debug?.modes){this.slothlet.debug("modes",{key:"DEBUG_MODE_CATEGORY_WRAPPER_CREATED",categoryName,apiPath:buildApiPath(categoryName)})}const wrapper=new UnifiedWrapper(this.slothlet,{mode:effectiveMode,apiPath:buildApiPath(categoryName),initialImpl,filePath:directory.path,moduleID:moduleID||categoryName,sourceFolder});api[categoryName]=wrapper.createProxy();if(this.slothlet.handlers?.metadata){this.slothlet.handlers.metadata.tagSystemMetadata(wrapper,{filePath:directory.path,apiPath:buildApiPath(categoryName),moduleID:moduleID||"base",sourceFolder:sourceFolder||directory.path},getInstanceToken(this.slothlet))}if(this.slothlet.config.debug?.modes){this.slothlet.debug("modes",{key:"DEBUG_MODE_CATEGORY_WRAPPER_ASSIGNED",categoryName})}targetApi=api[categoryName];if(this.slothlet.config.debug?.modes){this.slothlet.debug("modes",{key:"DEBUG_MODE_CATEGORY_CREATED",categoryName,apiPath:wrapper.apiPath});this.slothlet.debug("modes",{key:"DEBUG_MODE_CATEGORY_TARGET_API_STATUS",isWrapper:!!resolveWrapper(targetApi),targetApiKeys:Object.keys(targetApi)})}}}if(!isRoot&&this.slothlet.config.debug?.modes){this.slothlet.debug("modes",{message:await t("DEBUG_MODE_PROCESSING_DIRECTORY",{mode,categoryName,currentDepth})})}const loadedModules=[];for(const file of files){if(this.slothlet.config.debug?.modes&&categoryName==="string"){this.slothlet.debug("modes",{key:"DEBUG_MODE_PROCESSING_FILE",categoryName,file:file.name,isRoot,populateDirectly,mode})}try{const exports=file.synthetic?file.exports:this.slothlet.processors.loader.extractExports(await this.slothlet.processors.loader.loadModule(file.path,this.slothlet.instanceID,moduleID,cacheBust));const moduleName=this.slothlet.helpers.sanitize.sanitizePropertyName(file.name);const moduleKeys=Object.keys(exports).filter(k=>k!=="default");const analysis={hasDefault:exports.default!==void 0,hasNamed:moduleKeys.length>0,defaultExportType:exports.default?typeof exports.default:null};loadedModules.push({file,mod:exports,moduleName,moduleKeys,analysis})}catch(error){if(error.name==="SlothletError")throw error;throw new this.SlothletError("MODULE_LOAD_FAILED",{modulePath:file.path,moduleID:moduleID||file.moduleID},error)}}const hasMultipleDefaults=loadedModules.filter(m=>m.analysis.hasDefault).length>1;for(const{file,mod,moduleName,moduleKeys,analysis}of loadedModules){if(this.slothlet.config.debug?.modes&&categoryName==="logger"){this.slothlet.debug("modes",{key:"DEBUG_MODE_PROCESSING_MODULE",categoryName,moduleName,hasDefault:analysis.hasDefault,moduleKeys,targetApiType:typeof targetApi,targetApiCallable:typeof targetApi==="function"})}const isAddapiFile=moduleName==="addapi"||file.name==="addapi"||file.fullName&&["addapi.mjs","addapi.cjs","addapi.js","addapi.ts"].includes(file.fullName.toLowerCase());const isAddapiObjectDefault=isAddapiFile&&analysis.hasDefault&&typeof mod.default!=="function";const isRootContributor=isRoot&&analysis.hasDefault&&typeof mod.default==="function"&&!isAddapiObjectDefault;if(moduleName==="config"||moduleKeys.some(k=>k.includes("Config")||k.includes("config"))){if(this.slothlet.config.debug?.modes){this.slothlet.debug("modes",{key:"DEBUG_MODE_FILE_PROCESSING",module:moduleName,category:categoryName||"(none)",isRoot,hasDefault:analysis.hasDefault,moduleKeys})}}if(isRootContributor){const defaultFunc=this.slothlet.helpers.modesUtils.ensureNamedExportFunction(mod.default,moduleName);for(const key of moduleKeys){if(!this.slothlet.processors.flatten.shouldAttachNamedExport(key,mod[key],defaultFunc,mod.default)){continue}defaultFunc[key]=mod[key]}rootContributors.push({moduleName,file,defaultFunc});continue}else{const decision=await this.slothlet.processors.flatten.getFlatteningDecision({mod,moduleName,categoryName:categoryName||moduleName,analysis,hasMultipleDefaults,moduleKeys,t});if(this.slothlet.config.debug?.modes){this.slothlet.debug("modes",{message:await t("DEBUG_MODE_MODULE_DECISION",{mode,moduleName,reason:decision.reason})})}const propertyName=decision.preferredName||moduleName;const effectiveCategoryName=categoryName||moduleName;let{moduleContent}=this.slothlet.processors.flatten.processModuleForAPI({mod,decision,moduleName,propertyName,moduleKeys,analysis,file,collisionContext,apiPathPrefix:apiPathPrefix||""});if(!isRoot&&!apiPathPrefix&&moduleName===categoryName){if(moduleKeys.length===1&&moduleKeys[0]===moduleName&&!analysis.hasDefault){const exportedValue=mod[moduleName];if(typeof exportedValue==="object"&&exportedValue!==null){if(this.slothlet.config.debug?.modes&&categoryName==="string"){this.slothlet.debug("modes",{key:"DEBUG_MODE_SINGLE_FILE_FOLDER_DETECTED",categoryName,populateDirectly,isRoot,mode,exportKeys:Object.keys(exportedValue)})}if(shouldWrap){const wrapper=new UnifiedWrapper(this.slothlet,{mode:effectiveMode,apiPath:buildApiPath(categoryName),initialImpl:exportedValue,materializeOnCreate:this.slothlet.config.backgroundMaterialize,filePath:file.path,moduleID:moduleID||file.moduleID,sourceFolder});api[categoryName]=wrapper.createProxy();targetApi=api[categoryName]}else{this.slothlet.debug("modes",{key:"DEBUG_MODE_SINGLE_FILE_FOLDER_WRAPPED",categoryName,implKeys:Object.keys(exportedValue)})}for(const key of Object.keys(exportedValue)){if(this.slothlet.handlers.ownership){this.slothlet.handlers.ownership.register({moduleID:moduleID||file.moduleID,apiPath:`${categoryName}.${key}`,source:"core",collisionMode:this.slothlet.helpers.modesUtils.getOwnershipCollisionMode(this.slothlet.config,collisionContext),filePath:file.path})}}continue}}else if(analysis.hasDefault){const namedKeys=moduleKeys.length>0?moduleKeys:Object.keys(mod).filter(key=>key!=="default");const callableModule=typeof mod.default==="function"?this.slothlet.helpers.modesUtils.ensureNamedExportFunction(mod.default,categoryName):moduleContent;if(namedKeys.length>0){for(const key of namedKeys){if(key in callableModule){continue}if(!this.slothlet.processors.flatten.shouldAttachNamedExport(key,mod[key],callableModule,mod.default)){continue}callableModule[key]=mod[key]}}moduleContent=callableModule;if(shouldWrap){const wrapper=new UnifiedWrapper(this.slothlet,{mode:effectiveMode,apiPath:buildApiPath(categoryName),initialImpl:this.slothlet.helpers.modesUtils.cloneWrapperImpl(callableModule,mode),materializeOnCreate:this.slothlet.config.backgroundMaterialize,filePath:file.path,moduleID:moduleID||file.moduleID,sourceFolder});api[categoryName]=wrapper.createProxy();targetApi=api[categoryName]}else{api[categoryName]=moduleContent;targetApi=api[categoryName]}const needsSeparateNamedExports=typeof mod.default==="function";if(needsSeparateNamedExports&&namedKeys.length>0){for(const key of namedKeys){if(shouldWrap){const namedWrapper=new UnifiedWrapper(this.slothlet,{mode:effectiveMode,apiPath:buildApiPath(`${categoryName}.${key}`),initialImpl:mod[key],materializeOnCreate:this.slothlet.config.backgroundMaterialize,filePath:file.path,moduleID:moduleID||file.moduleID,sourceFolder});this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,key,namedWrapper.createProxy(),{useCollisionDetection:true,config:this.slothlet.config,collisionContext})}else{this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,key,mod[key],{useCollisionDetection:true,config:this.slothlet.config,collisionContext})}if(this.slothlet.handlers.ownership){this.slothlet.handlers.ownership.register({moduleID:moduleID||file.moduleID,apiPath:`${categoryName}.${key}`,source:"core",collisionMode:this.slothlet.helpers.modesUtils.getOwnershipCollisionMode(this.slothlet.config,collisionContext),filePath:file.path})}}}if(this.slothlet.handlers.ownership){this.slothlet.handlers.ownership.register({moduleID:moduleID||file.moduleID,apiPath:categoryName,source:"core",collisionMode:this.slothlet.helpers.modesUtils.getOwnershipCollisionMode(this.slothlet.config,collisionContext),filePath:file.path})}continue}else if(moduleKeys.length>0){const hasMatchingObject=moduleKeys.some(key=>key===moduleName&&typeof mod[key]==="object"&&mod[key]!==null&&!Array.isArray(mod[key]));if(hasMatchingObject){const matchingObj=mod[moduleName];for(const[propKey,propValue]of Object.entries(matchingObj)){if(shouldWrap){const wrapper=new UnifiedWrapper(this.slothlet,{mode:effectiveMode,apiPath:buildApiPath(`${categoryName}.${propKey}`),initialImpl:this.slothlet.helpers.modesUtils.cloneWrapperImpl(propValue,mode),materializeOnCreate:this.slothlet.config.backgroundMaterialize,filePath:file.path,moduleID:moduleID||file.moduleID,sourceFolder});this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,propKey,wrapper.createProxy(),{useCollisionDetection:true,config:this.slothlet.config,collisionContext})}else{this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,propKey,propValue,{useCollisionDetection:true,config:this.slothlet.config,collisionContext})}if(this.slothlet.handlers.ownership){this.slothlet.handlers.ownership.register({moduleID:moduleID||file.moduleID,apiPath:`${categoryName}.${propKey}`,source:"core",collisionMode:this.slothlet.helpers.modesUtils.getOwnershipCollisionMode(this.slothlet.config,collisionContext),filePath:file.path})}}for(const key of moduleKeys){if(key!==moduleName){if(shouldWrap){const wrapper=new UnifiedWrapper(this.slothlet,{mode:effectiveMode,apiPath:buildApiPath(`${categoryName}.${key}`),initialImpl:this.slothlet.helpers.modesUtils.cloneWrapperImpl(mod[key],mode),materializeOnCreate:this.slothlet.config.backgroundMaterialize,filePath:file.path,moduleID:moduleID||file.moduleID,sourceFolder});this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,key,wrapper.createProxy(),{useCollisionDetection:true,config:this.slothlet.config,collisionContext})}else{this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,key,mod[key],{useCollisionDetection:true,config:this.slothlet.config,collisionContext})}if(this.slothlet.handlers.ownership){this.slothlet.handlers.ownership.register({moduleID:moduleID||file.moduleID,apiPath:`${categoryName}.${key}`,source:"core",collisionMode:this.slothlet.helpers.modesUtils.getOwnershipCollisionMode(this.slothlet.config,collisionContext),filePath:file.path})}}}}else{if(this.slothlet.config.debug?.modes){this.slothlet.debug("modes",{key:"DEBUG_MODE_FLATTEN_MULTI_EXPORT_FILE",moduleName,categoryName,exportCount:moduleKeys.length});this.slothlet.debug("modes",{key:"DEBUG_MODE_FLATTEN_MULTI_EXPORT_TARGET_STATUS",isWrapper:!!resolveWrapper(targetApi),keysBefore:Object.keys(targetApi)})}for(const key of moduleKeys){if(this.slothlet.config.debug?.modes){this.slothlet.debug("modes",{key:"DEBUG_MODE_FLATTEN_MULTI_EXPORT_ASSIGNING",propKey:key})}if(shouldWrap){const wrapper=new UnifiedWrapper(this.slothlet,{mode:effectiveMode,apiPath:buildApiPath(`${categoryName}.${key}`),initialImpl:this.slothlet.helpers.modesUtils.cloneWrapperImpl(mod[key],mode),materializeOnCreate:this.slothlet.config.backgroundMaterialize,filePath:file.path,moduleID:moduleID||file.moduleID,sourceFolder});const assigned=this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,key,wrapper.createProxy(),{useCollisionDetection:true,config:this.slothlet.config,collisionContext});if(assigned){this.slothlet.debug("modes",{key:"DEBUG_MODE_FLATTEN_MULTI_EXPORT_ASSIGNED",propKey:key,keysAfter:Object.keys(targetApi)})}else{this.slothlet.debug("modes",{key:"DEBUG_MODE_FLATTEN_MULTI_EXPORT_BLOCKED",propKey:key})}}else{this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,key,mod[key],{useCollisionDetection:true,config:this.slothlet.config,collisionContext})}if(this.slothlet.handlers.ownership){this.slothlet.handlers.ownership.register({moduleID:moduleID||file.moduleID,apiPath:`${categoryName}.${key}`,source:"core",collisionMode:this.slothlet.helpers.modesUtils.getOwnershipCollisionMode(this.slothlet.config,collisionContext),filePath:file.path})}}}continue}}if(!analysis.hasDefault&&moduleKeys.length===1&&!isRoot){const key=moduleKeys[0];const keyValue=mod[key];const isMatchingObject=key===moduleName&&typeof keyValue==="object"&&keyValue!==null&&!Array.isArray(keyValue);if(!isMatchingObject){const normalizedKey=key.toLowerCase().replace(/[-_]/g,"");const normalizedModuleName=moduleName.toLowerCase().replace(/[-_]/g,"");if(normalizedKey===normalizedModuleName){const preferredName=key;if(shouldWrap){const wrapper=new UnifiedWrapper(this.slothlet,{mode:effectiveMode,apiPath:buildApiPath(`${categoryName}.${preferredName}`),initialImpl:this.slothlet.helpers.modesUtils.cloneWrapperImpl(mod[key],mode),materializeOnCreate:this.slothlet.config.backgroundMaterialize,filePath:file.path,moduleID:moduleID||file.moduleID,sourceFolder});this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,preferredName,wrapper.createProxy(),{useCollisionDetection:true,config:this.slothlet.config,collisionContext})}else{this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,preferredName,mod[key],{useCollisionDetection:true,config:this.slothlet.config,collisionContext})}if(this.slothlet.handlers.ownership){this.slothlet.handlers.ownership.register({moduleID:moduleID||file.moduleID,apiPath:`${categoryName}.${preferredName}`,source:"core",collisionMode:this.slothlet.helpers.modesUtils.getOwnershipCollisionMode(this.slothlet.config,collisionContext),filePath:file.path})}continue}}}if(decision.flattenToRoot&&moduleContent&&!isRoot&&!this.slothlet.config.suppressFixes?.has("C03_116")){for(const key of Object.keys(moduleContent)){const value=moduleContent[key];const keyPath=apiPathPrefix?`${apiPathPrefix}.${key}`:`${categoryName}.${key}`;if(shouldWrap&&typeof value==="function"){const wrapper=new UnifiedWrapper(this.slothlet,{mode:effectiveMode,apiPath:buildApiPath(keyPath),initialImpl:value,materializeOnCreate:this.slothlet.config.backgroundMaterialize,filePath:file.path,moduleID:moduleID||file.moduleID,sourceFolder});this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,key,wrapper.createProxy(),{useCollisionDetection:true,config:this.slothlet.config,collisionContext})}else{this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,key,value,{useCollisionDetection:true,config:this.slothlet.config,collisionContext})}}if(this.slothlet.handlers.ownership){for(const key of Object.keys(moduleContent)){const apiPath=apiPathPrefix?`${apiPathPrefix}.${key}`:`${categoryName}.${key}`;this.slothlet.handlers.ownership.register({moduleID:moduleID||file.moduleID,apiPath,source:"core",collisionMode:this.slothlet.helpers.modesUtils.getOwnershipCollisionMode(this.slothlet.config,collisionContext),filePath:file.path})}}continue}if(decision.flattenToCategory&&moduleContent&&effectiveCategoryName){const isAddapiFile2=decision.flattenType==="addapi-metadata-default"||decision.flattenType==="addapi-special-file";if(isAddapiFile2&&typeof moduleContent==="object"&&!Array.isArray(moduleContent)&&typeof moduleContent!=="function"){for(const key of Object.keys(moduleContent)){const value=moduleContent[key];const keyPath=isRoot?key:`${apiPathPrefix?apiPathPrefix+".":""}${key}`;if(shouldWrap&&typeof value==="function"){const wrapper=new UnifiedWrapper(this.slothlet,{mode:effectiveMode,apiPath:buildApiPath(keyPath),initialImpl:value,materializeOnCreate:this.slothlet.config.backgroundMaterialize,filePath:file.path,moduleID:moduleID||file.moduleID,sourceFolder});this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,key,wrapper.createProxy(),{useCollisionDetection:true,config:this.slothlet.config,collisionContext})}else{this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,key,value,{useCollisionDetection:true,config:this.slothlet.config,collisionContext})}}if(this.slothlet.handlers.ownership){for(const key of Object.keys(moduleContent)){const apiPath=isRoot?key:apiPathPrefix?`${apiPathPrefix}.${key}`:key;this.slothlet.handlers.ownership.register({moduleID:moduleID||file.moduleID,apiPath,source:"core",collisionMode:this.slothlet.helpers.modesUtils.getOwnershipCollisionMode(this.slothlet.config,collisionContext),config:this.slothlet.config})}}}else{const localPath=isRoot?effectiveCategoryName:`${apiPathPrefix?apiPathPrefix+".":""}${effectiveCategoryName}`;if(shouldWrap){const wrapper=new UnifiedWrapper(this.slothlet,{mode:effectiveMode,apiPath:buildApiPath(localPath),initialImpl:moduleContent,materializeOnCreate:this.slothlet.config.backgroundMaterialize,filePath:file.path,moduleID:moduleID||file.moduleID,sourceFolder,isCallable:typeof moduleContent==="function"});this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,effectiveCategoryName,wrapper.createProxy(),{useCollisionDetection:true,config:this.slothlet.config,collisionContext})}else{this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,effectiveCategoryName,moduleContent,{useCollisionDetection:true,config:this.slothlet.config,collisionContext})}if(this.slothlet.handlers.ownership){const apiPath=isRoot?effectiveCategoryName:apiPathPrefix?`${apiPathPrefix}.${effectiveCategoryName}`:effectiveCategoryName;this.slothlet.handlers.ownership.register({moduleID:moduleID||file.moduleID,apiPath,source:"core",collisionMode:this.slothlet.helpers.modesUtils.getOwnershipCollisionMode(this.slothlet.config,collisionContext),config:this.slothlet.config})}}continue}if(shouldWrap){const localPath=isRoot?propertyName:`${categoryName}.${propertyName}`;const wrapper=new UnifiedWrapper(this.slothlet,{mode:effectiveMode,apiPath:buildApiPath(localPath),initialImpl:moduleContent,materializeOnCreate:this.slothlet.config.backgroundMaterialize,filePath:file.path,moduleID:moduleID||file.moduleID,sourceFolder});this.slothlet.debug("modes",{key:"DEBUG_MODE_FILE_WRAPPER_ASSIGNMENT",propertyName,apiPath:buildApiPath(localPath),overwriting:propertyName in targetApi?resolveWrapper(targetApi[propertyName])?"wrapper":"value":"nothing"});this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,propertyName,wrapper.createProxy(),{useCollisionDetection:true,config:this.slothlet.config,collisionContext})}else{this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,propertyName,moduleContent,{useCollisionDetection:true,config:this.slothlet.config,collisionContext})}if(this.slothlet.config.debug?.modes&&categoryName==="logger"){this.slothlet.debug("modes",{key:"DEBUG_MODE_AFTER_ASSIGNMENT_STATUS",targetApiType:typeof targetApi,propertyName,hasProperty:propertyName in targetApi,implType:typeof resolveWrapper(targetApi)?.____slothletInternal.impl,implHasProperty:!!resolveWrapper(targetApi)?.____slothletInternal.impl?.utils})}if(this.slothlet.handlers.ownership){const apiPath=buildApiPath(isRoot?propertyName:`${categoryName}.${propertyName}`);this.slothlet.handlers.ownership.register({moduleID:moduleID||file.moduleID,apiPath,source:"core",collisionMode:this.slothlet.helpers.modesUtils.getOwnershipCollisionMode(this.slothlet.config,collisionContext),config:this.slothlet.config})}}}if(this.slothlet.config.debug?.modes){this.slothlet.debug("modes",{key:"DEBUG_MODE_SUBDIRECTORY_CHECK",isRoot,categoryName,hasDirectory:!!directory,hasChildren:!!directory?.children,directoryCount:directory?.children?.directories?.length||0})}this.slothlet.debug("modes",{key:"DEBUG_MODE_DIRECTORY_CHECK",hasChildren:!!directory?.children,hasDirectories:!!directory?.children?.directories,length:directory?.children?.directories?.length||0});if(directory?.children?.directories){this.slothlet.debug("modes",{key:"DEBUG_MODE_DIRECTORY_CHECK_PASSED",recursive});if(this.slothlet.config.debug?.modes){this.slothlet.debug("modes",{key:"DEBUG_MODE_SUBDIRECTORIES_FOUND",subdirectoryCount:directory.children.directories.length,recursive})}if(recursive){this.slothlet.debug("modes",{key:"DEBUG_MODE_SUBDIRECTORY_LOOP_START",count:directory.children.directories.length});for(const subDir of directory.children.directories){this.slothlet.debug("modes",{key:"DEBUG_MODE_PROCESSING_SUBDIRECTORY",name:subDir.name,fileCount:subDir.children.files.length,subdirCount:subDir.children.directories.length});const subDirName=this.slothlet.helpers.sanitize.sanitizePropertyName(subDir.name);if(subDir.children.files.length===1&&subDir.children.directories.length===0){const file=subDir.children.files[0];const moduleName=this.slothlet.helpers.sanitize.sanitizePropertyName(file.name);const genericFilenames=["singlefile","index","main","default"];const isGeneric=genericFilenames.includes(moduleName.toLowerCase());const filenameMatchesFolder=moduleName===subDirName;if(isGeneric||filenameMatchesFolder){this.slothlet.debug("modes",{key:"DEBUG_MODE_FOLDER_LEVEL_FLATTEN_CHECK",subDir:subDirName,file:moduleName,isGeneric,filenameMatches:filenameMatchesFolder});const mod=await this.slothlet.processors.loader.loadModule(file.path,this.slothlet.instanceID,moduleID,cacheBust);const exports=this.slothlet.processors.loader.extractExports(mod);const moduleKeys=Object.keys(exports).filter(k=>k!=="default");const analysis={hasDefault:exports.default!==void 0,hasNamed:moduleKeys.length>0,defaultExportType:exports.default?typeof exports.default:null};const modContent=exports.default!==void 0?exports.default:exports;const categoryDecision=await this.slothlet.processors.flatten.buildCategoryDecisions({categoryName:subDirName,mod:modContent,moduleName,fileBaseName:file.name,analysis,moduleKeys,currentDepth:currentDepth+1,moduleFiles:subDir.children.files,t});if(categoryDecision.shouldFlatten){this.slothlet.debug("modes",{key:"DEBUG_MODE_FOLDER_LEVEL_FLATTEN_SKIP_RECURSION",subDir:subDirName});let implToWrap;if(categoryDecision.flattenType==="addapi-metadata-default"){implToWrap={};for(const key of moduleKeys){if(key!=="default"){implToWrap[key]=exports[key]}}}else if(moduleName===subDirName&&moduleKeys.includes(subDirName)){implToWrap=exports[subDirName]}else if(exports.default!==void 0){implToWrap=exports.default;if(moduleKeys.length>0){if(typeof implToWrap==="function"){const collisionConfig=this.slothlet.config.api?.collision||this.slothlet.config.collision;const collisionMode=(collisionContext==="initial"?collisionConfig?.initial:collisionConfig?.api)||"merge";for(const key of moduleKeys){if(key!=="default"){const hasExisting=implToWrap[key]!==void 0;if(hasExisting){if(collisionMode==="merge"||collisionMode==="skip"){continue}else if(collisionMode==="error"){throw new this.slothlet.SlothletError("COLLISION_DEFAULT_EXPORT_ERROR",{key,apiPath:`${apiPathPrefix}.${subDirName}`},null,{validationError:true})}else if(collisionMode==="warn"){new this.slothlet.SlothletWarning("WARNING_COLLISION_DEFAULT_EXPORT_OVERWRITE",{key,apiPath:`${apiPathPrefix}.${subDirName}`})}}implToWrap[key]=exports[key]}}}else if(typeof implToWrap==="object"&&implToWrap!==null){for(const key of moduleKeys){if(key!=="default"&&!(key in implToWrap)){implToWrap[key]=exports[key]}}}}}else{implToWrap=modContent}const modes_eagerCollisionConfig=this.slothlet.config.api?.collision||this.slothlet.config.collision;const modes_eagerCollisionMode=(collisionContext==="initial"?modes_eagerCollisionConfig?.initial:modes_eagerCollisionConfig?.api)||"merge";const modes_existingAtKey=targetApi[subDirName];if(modes_existingAtKey!==void 0&&modes_eagerCollisionMode!=="replace"&&modes_eagerCollisionMode!=="skip"){const modes_existingWrapper=resolveWrapper(modes_existingAtKey);if(modes_existingWrapper){if(modes_existingWrapper.____slothletInternal?.materializeFunc&&!modes_existingWrapper.____slothletInternal?.state?.materialized){await modes_existingWrapper._materialize()}if(modes_existingWrapper.____slothletInternal?.impl&&!modes_existingWrapper.____slothletInternal?.state?.childrenAdopted){modes_existingWrapper.___adoptImplChildren()}const modes_existingImpl=modes_existingWrapper.__impl;if(modes_existingImpl&&typeof modes_existingImpl==="object"&&!Array.isArray(modes_existingImpl)){if(typeof implToWrap==="object"&&implToWrap!==null){for(const[k,v]of Object.entries(modes_existingImpl)){if(!(k in implToWrap)){implToWrap[k]=v}}}else if(typeof implToWrap==="function"){for(const[k,v]of Object.entries(modes_existingImpl)){if(implToWrap[k]===void 0){implToWrap[k]=v}}}}const modes_existingChildKeys=Object.keys(modes_existingWrapper).filter(k=>!k.startsWith("_")&&!k.startsWith("__"));for(const ck of modes_existingChildKeys){if(typeof implToWrap==="object"&&implToWrap!==null&&!(ck in implToWrap)){implToWrap[ck]=modes_existingWrapper[ck]}else if(typeof implToWrap==="function"&&implToWrap[ck]===void 0){implToWrap[ck]=modes_existingWrapper[ck]}}this.slothlet.debug("modes",{key:"DEBUG_MODE_FILE_FOLDER_COLLISION_MERGED",subDir:subDirName,mergedKeys:Object.keys(implToWrap)})}}const wrapper=new UnifiedWrapper(this.slothlet,{mode:effectiveMode,apiPath:buildApiPath(categoryName?`${categoryName}.${subDirName}`:subDirName),initialImpl:implToWrap,materializeOnCreate:this.slothlet.config.backgroundMaterialize,filePath:file.path,moduleID:moduleID||file.moduleID,sourceFolder});this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,subDirName,wrapper.createProxy(),{useCollisionDetection:true,config:this.slothlet.config,collisionContext});if(this.slothlet.handlers.ownership){const apiPath=buildApiPath(categoryName?`${categoryName}.${subDirName}`:subDirName);this.slothlet.handlers.ownership.register({moduleID:moduleID||file.moduleID,apiPath,source:"core",collisionMode:this.slothlet.helpers.modesUtils.getOwnershipCollisionMode(this.slothlet.config,collisionContext),config:this.slothlet.config})}continue}}}const currentCategoryName=apiPathPrefix?apiPathPrefix.split(".").pop():categoryName;if(subDirName===currentCategoryName&&currentCategoryName!==null){await this.processFiles(targetApi,subDir.children.files,subDir,currentDepth+1,mode,false,recursive,true,apiPathPrefix,collisionContext,moduleID,sourceFolder,cacheBust);continue}await this.processFiles(targetApi,subDir.children.files,{name:subDirName,path:subDir.path,children:subDir.children},currentDepth+1,mode,false,recursive,false,apiPathPrefix,collisionContext,moduleID,sourceFolder,cacheBust)}}else{for(const subDir of directory.children.directories){const subDirName=this.slothlet.helpers.sanitize.sanitizePropertyName(subDir.name);const lazy_currentCategoryName=apiPathPrefix?apiPathPrefix.split(".").pop():categoryName;if(subDirName===lazy_currentCategoryName&&lazy_currentCategoryName!==null&&!populateDirectly){await this.processFiles(targetApi,subDir.children.files,subDir,currentDepth+1,"eager",false,true,true,apiPathPrefix,collisionContext,moduleID,sourceFolder,cacheBust);continue}const apiPath=categoryName?`${categoryName}.${subDirName}`:apiPathPrefix?`${apiPathPrefix}.${subDirName}`:subDirName;if(this.slothlet.config.debug?.modes){this.slothlet.debug("modes",{key:"DEBUG_MODE_CREATING_LAZY_SUBDIRECTORY",apiPath,fileCount:subDir.children.files.length})}const collisionConfig=this.slothlet.config.api?.collision;const modes_initialCollisionMode=collisionModeOverride||(collisionContext==="initial"?collisionConfig?.initial:collisionConfig?.api)||"replace";let modes_fileFolderImpl=null;const modes_lazyExisting=targetApi[subDirName];if(modes_initialCollisionMode!=="replace"&&resolveWrapper(modes_lazyExisting)){const modes_lazyExistingW=resolveWrapper(modes_lazyExisting);const existImpl=modes_lazyExistingW.__impl;if(existImpl&&typeof existImpl==="object"&&!Array.isArray(existImpl)){modes_fileFolderImpl={...existImpl}}const existChildKeys=Object.keys(modes_lazyExistingW).filter(k=>!k.startsWith("_")&&!k.startsWith("__"));for(const ck of existChildKeys){if(!modes_fileFolderImpl)modes_fileFolderImpl={};if(!(ck in modes_fileFolderImpl)){modes_fileFolderImpl[ck]=modes_lazyExistingW[ck]}}}this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,subDirName,this.createLazySubdirectoryWrapper(subDir,apiPath,moduleID,sourceFolder,cacheBust,modes_fileFolderImpl,modes_initialCollisionMode),{useCollisionDetection:true,config:this.slothlet.config,collisionContext})}}}if(isRoot&&rootContributors.length>0){if(rootContributors.length===1){const{moduleName,file,defaultFunc}=rootContributors[0];rootDefaultFunction=defaultFunc;if(this.slothlet.config.debug?.modes){this.slothlet.debug("modes",{message:await t("DEBUG_MODE_ROOT_CONTRIBUTOR",{mode,functionName:defaultFunc.name||"anonymous"})})}if(this.slothlet.handlers.ownership){this.slothlet.handlers.ownership.register({moduleID:moduleID||file.moduleID,apiPath:moduleName,source:"core",collisionMode:this.slothlet.helpers.modesUtils.getOwnershipCollisionMode(this.slothlet.config,collisionContext),filePath:file.path})}}else{new this.SlothletWarning("WARNING_MULTIPLE_ROOT_CONTRIBUTORS",{rootContributors:rootContributors.map(rc=>rc.moduleName).join(", "),firstContributor:rootContributors[0].moduleName});for(const{moduleName,file,defaultFunc}of rootContributors){if(shouldWrap){const wrapper=new UnifiedWrapper(this.slothlet,{mode:effectiveMode,apiPath:buildApiPath(moduleName),initialImpl:this.slothlet.helpers.modesUtils.cloneWrapperImpl(defaultFunc,mode),materializeOnCreate:this.slothlet.config.backgroundMaterialize,filePath:file.path,moduleID:moduleID||file.moduleID,sourceFolder});this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,moduleName,wrapper.createProxy(),{useCollisionDetection:true,config:this.slothlet.config,collisionContext})}else{this.slothlet.builders.apiAssignment.assignToApiPath(targetApi,moduleName,defaultFunc,{useCollisionDetection:true,config:this.slothlet.config,collisionContext})}if(this.slothlet.handlers.ownership){this.slothlet.handlers.ownership.register({moduleID:moduleID||file.moduleID,apiPath:moduleName,source:"core",collisionMode:this.slothlet.helpers.modesUtils.getOwnershipCollisionMode(this.slothlet.config,collisionContext),filePath:file.path})}}}}return rootDefaultFunction}createLazySubdirectoryWrapper(dir,apiPath,moduleID=null,sourceFolder=null,cacheBust=null,fileFolderCollisionImpl=null,collisionMode="merge"){const lazy_materializeFunc=this.slothlet.modes.lazy.createNamedMaterializeFunc(apiPath,async()=>{if(this.slothlet.config.debug?.modes){this.slothlet.debug("modes",{key:"DEBUG_MODE_MATERIALIZE_FUNCTION_STARTING",dir:dir.name,fileCount:dir.children.files?.length||0})}const categoryName=this.slothlet.helpers.sanitize.sanitizePropertyName(dir.name);const materialized={};const actualSourceFolder=sourceFolder?`${sourceFolder}/${dir.name}`.replace(/\\/g,"/"):`${this.slothlet.config?.dir}/${dir.name}`.replace(/\\/g,"/");const parentPrefix=apiPath.includes(".")?apiPath.split(".").slice(0,-1).join("."):"";const subDirs=dir.children.directories||[];if(dir.children.files.length===1&&subDirs.length===0){const file=dir.children.files[0];const moduleName=this.slothlet.helpers.sanitize.sanitizePropertyName(file.name);const genericFilenames=["singlefile","index","main","default"];const isGeneric=genericFilenames.includes(moduleName.toLowerCase());const filenameMatchesFolder=moduleName===categoryName;if(isGeneric||filenameMatchesFolder){const mod=await this.slothlet.processors.loader.loadModule(file.path,this.slothlet.instanceID,moduleID,cacheBust);const exports=this.slothlet.processors.loader.extractExports(mod);const moduleKeys=Object.keys(exports).filter(k=>k!=="default");const analysis={hasDefault:exports.default!==void 0,hasNamed:moduleKeys.length>0,defaultExportType:exports.default?typeof exports.default:null};const modContent=exports.default!==void 0?exports.default:exports;const categoryDecision=await this.slothlet.processors.flatten.buildCategoryDecisions({categoryName,mod:modContent,moduleName,fileBaseName:file.name,analysis,moduleKeys,currentDepth:apiPath.split(".").length,moduleFiles:dir.children.files,t});if(categoryDecision.shouldFlatten){let implToWrap;if(categoryDecision.flattenType==="addapi-metadata-default"){implToWrap=exports.default;for(const key of moduleKeys){if(key!=="default"){implToWrap[key]=exports[key]}}}else if(moduleName===categoryName&&moduleKeys.includes(categoryName)){implToWrap=exports[categoryName]}else if(exports.default!==void 0){implToWrap=exports.default;if(moduleKeys.length>0&&(typeof implToWrap==="function"||typeof implToWrap==="object"&&implToWrap!==null)){const collisionMode2=this.slothlet.config?.collision?.initial||"merge";for(const key of moduleKeys){if(!this.slothlet.processors.flatten.shouldAttachNamedExport(key,exports[key],implToWrap,exports.default)){continue}const hasExisting=Object.prototype.hasOwnProperty.call(implToWrap,key);if(hasExisting){if(collisionMode2==="merge"||collisionMode2==="skip"){continue}else if(collisionMode2==="error"){throw new this.slothlet.SlothletError("COLLISION_DEFAULT_EXPORT_ERROR",{key,apiPath},null,{validationError:true})}else if(collisionMode2==="warn"){new this.slothlet.SlothletWarning("WARNING_COLLISION_DEFAULT_EXPORT_OVERWRITE",{key,apiPath})}}implToWrap[key]=exports[key]}}}else{implToWrap=modContent}if(implToWrap&&typeof implToWrap==="object"&&this.slothlet.handlers?.lifecycle){for(const key of Object.keys(implToWrap)){const value=implToWrap[key];if(typeof value==="function"){this.slothlet.handlers.lifecycle.emit("impl:created",{apiPath:`${apiPath}.${key}`,impl:value,source:"lazy-materialization",moduleID,filePath:file.path,sourceFolder:sourceFolder||this.slothlet.config?.dir})}}}if(implToWrap&&typeof implToWrap==="object"){const childPaths={};for(const key of Object.keys(implToWrap)){if(typeof key!=="symbol"&&key!=="__childFilePaths"&&key!=="__filePath"){childPaths[key]=file.path}}implToWrap.__childFilePaths=childPaths}if(fileFolderCollisionImpl&&typeof implToWrap==="object"&&implToWrap!==null){for(const[k,v]of Object.entries(fileFolderCollisionImpl)){if(!(k in implToWrap)){implToWrap[k]=v}}}else if(fileFolderCollisionImpl&&typeof implToWrap==="function"){for(const[k,v]of Object.entries(fileFolderCollisionImpl)){if(implToWrap[k]===void 0){implToWrap[k]=v}}}return implToWrap}}}await this.processFiles(materialized,dir.children.files,{name:dir.name,children:dir.children},0,"eager",false,false,true,parentPrefix,"initial",moduleID,actualSourceFolder,cacheBust,collisionMode);if(this.slothlet.config.debug?.modes){this.slothlet.debug("modes",{key:"DEBUG_MODE_MATERIALIZE_FUNCTION_RETURNING_IMPL",dir:dir.name,keys:Object.keys(materialized)})}if(fileFolderCollisionImpl){for(const[k,v]of Object.entries(fileFolderCollisionImpl)){if(!(k in materialized)){materialized[k]=v}}}const materializedKeys=Object.keys(materialized);const _hasCategoryFile=dir.children.files.some(f=>this.slothlet.helpers.sanitize.sanitizePropertyName(f.name)===categoryName);if(_hasCategoryFile&&materializedKeys.includes(categoryName)&&materializedKeys.length>1){if(this.slothlet.config.debug?.modes){this.slothlet.debug("modes",{key:"DEBUG_MODE_FOLDER_PATTERN_MATCH",dir:dir.name,categoryName,keys:materializedKeys})}const mainValue=materialized[categoryName];for(const key of materializedKeys){if(key!==categoryName){if(this.slothlet.config.debug?.modes){this.slothlet.debug("modes",{key:"DEBUG_MODE_FOLDER_PATTERN_ATTACH_PROPERTY",categoryName,propKey:key,valueType:typeof materialized[key]})}mainValue[key]=materialized[key]}}if(this.slothlet.config.debug?.modes){this.slothlet.debug("modes",{key:"DEBUG_MODE_FOLDER_PATTERN_RETURN",categoryName,keys:Object.keys(mainValue).filter(k=>!k.startsWith("__"))})}return mainValue}if(materializedKeys.length===1&&materializedKeys[0]===categoryName){const nestedValue=materialized[categoryName];if(nestedValue&&resolveWrapper(nestedValue)!==null){const attachedKeys=Object.keys(nestedValue).filter(key=>key!=="____slothletInternal");if(attachedKeys.length>0){return nestedValue}return nestedValue.__impl??nestedValue}else{return nestedValue}}return materialized});const wrapper=new UnifiedWrapper(this.slothlet,{mode:"lazy",apiPath,materializeFunc:lazy_materializeFunc,materializeOnCreate:this.slothlet.config.backgroundMaterialize,filePath:dir.path,moduleID,sourceFolder});if(collisionMode){wrapper.____slothletInternal.state.collisionMode=collisionMode}const shouldPrePopulate=collisionMode==="merge"||collisionMode==="warn";if(fileFolderCollisionImpl&&shouldPrePopulate){for(const[k,v]of Object.entries(fileFolderCollisionImpl)){if(typeof k==="string"&&!k.startsWith("_")&&!k.startsWith("__")){Object.defineProperty(wrapper,k,{value:v,writable:false,enumerable:true,configurable:true})}}}return wrapper.createProxy()}async applyRootContributor(api,rootFunction,mode){if(rootFunction){Object.assign(rootFunction,api);if(this.slothlet.config.debug?.modes){this.slothlet.debug("modes",{message:await t("DEBUG_MODE_ROOT_CONTRIBUTOR_APPLIED",{mode,properties:Object.keys(api).length})})}return rootFunction}return api}}export{ModesProcessor};
@@ -14,4 +14,4 @@
14
14
  limitations under the License.
15
15
  */
16
16
 
17
- import{ComponentBase}from"@cldmv/slothlet/factories/component-base";class ApiCacheManager extends ComponentBase{static slothletProperty="apiCacheManager";constructor(slothlet){super(slothlet);this.caches=new Map}set(moduleID,entry){if(!moduleID||typeof moduleID!=="string"){throw new this.SlothletError("INVALID_ARGUMENT",{argument:"moduleID",expected:"non-empty string",received:typeof moduleID,validationError:true})}if(!entry||!entry.api){throw new this.SlothletError("INVALID_ARGUMENT",{argument:"entry.api",expected:"API tree object",received:typeof entry?.api,validationError:true})}if(entry.moduleID&&entry.moduleID!==moduleID){throw new this.SlothletError("CACHE_MODULEID_MISMATCH",{cacheKey:moduleID,entryModuleID:entry.moduleID,validationError:true})}this.caches.set(moduleID,entry);this.slothlet.debug("cache",{key:"DEBUG_MODE_CACHE_ENTRY_STORED",moduleID,endpoint:entry.endpoint,mode:entry.mode,timestamp:entry.timestamp})}get(moduleID){return this.caches.get(moduleID)}has(moduleID){return this.caches.has(moduleID)}delete(moduleID){const deleted=this.caches.delete(moduleID);if(deleted){this.slothlet.debug("cache",{key:"DEBUG_MODE_CACHE_ENTRY_DELETED",moduleID})}return deleted}getAllModuleIDs(){return Array.from(this.caches.keys())}getCacheDiagnostics(){const caches=[];for(const[moduleID,entry]of this.caches.entries()){const pathCount=this._countPaths(entry.api);caches.push({moduleID,endpoint:entry.endpoint,folderPath:entry.folderPath,mode:entry.mode,pathCount,timestamp:entry.timestamp})}return{totalCaches:this.caches.size,caches}}_countPaths(api,visited=new WeakSet){if(!api||typeof api!=="object"||visited.has(api)){return 0}visited.add(api);let count=0;for(const[key,value]of Object.entries(api)){if(key.startsWith("__")||key.startsWith("_")){continue}count+=1;if(value&&typeof value==="object"){count+=this._countPaths(value,visited)}}return count}clear(){this.caches.clear();this.slothlet.debug("cache",{key:"DEBUG_MODE_ALL_CACHES_CLEARED"})}async rebuildCache(moduleID){const entry=this.get(moduleID);if(!entry){throw new this.SlothletError("CACHE_NOT_FOUND",{moduleID,operation:"rebuild",validationError:true})}this.slothlet.debug("cache",{key:"DEBUG_MODE_REBUILDING_CACHE_FROM_DISK",moduleID,folderPath:entry.folderPath,mode:entry.mode});const freshApi=await this.slothlet.builders.builder.buildAPI({dir:entry.folderPath,mode:entry.mode,sanitize:entry.sanitizeOptions,moduleID,apiPathPrefix:entry.endpoint==="."?"":entry.endpoint,collisionMode:entry.collisionMode,collisionContext:entry.endpoint==="."?"initial":"addApi",cacheBust:Date.now()});this.slothlet.debug("cache",{key:"DEBUG_MODE_CACHE_REBUILT_SUCCESSFULLY",moduleID,timestamp:Date.now()});return freshApi}}export{ApiCacheManager};
17
+ import{ComponentBase}from"@cldmv/slothlet/factories/component-base";class ApiCacheManager extends ComponentBase{static slothletProperty="apiCacheManager";constructor(slothlet){super(slothlet);this.caches=new Map}set(moduleID,entry){if(!moduleID||typeof moduleID!=="string"){throw new this.SlothletError("INVALID_ARGUMENT",{argument:"moduleID",expected:"non-empty string",received:typeof moduleID,validationError:true})}if(!entry||!entry.api){throw new this.SlothletError("INVALID_ARGUMENT",{argument:"entry.api",expected:"API tree object",received:typeof entry?.api,validationError:true})}if(entry.moduleID&&entry.moduleID!==moduleID){throw new this.SlothletError("CACHE_MODULEID_MISMATCH",{cacheKey:moduleID,entryModuleID:entry.moduleID,validationError:true})}this.caches.set(moduleID,entry);this.slothlet.debug("cache",{key:"DEBUG_MODE_CACHE_ENTRY_STORED",moduleID,endpoint:entry.endpoint,mode:entry.mode,timestamp:entry.timestamp})}get(moduleID){return this.caches.get(moduleID)}has(moduleID){return this.caches.has(moduleID)}delete(moduleID){const deleted=this.caches.delete(moduleID);if(deleted){this.slothlet.debug("cache",{key:"DEBUG_MODE_CACHE_ENTRY_DELETED",moduleID})}return deleted}getAllModuleIDs(){return Array.from(this.caches.keys())}getCacheDiagnostics(){const caches=[];for(const[moduleID,entry]of this.caches.entries()){const pathCount=this._countPaths(entry.api);caches.push({moduleID,endpoint:entry.endpoint,folderPath:entry.folderPath,mode:entry.mode,pathCount,timestamp:entry.timestamp})}return{totalCaches:this.caches.size,caches}}_countPaths(api,visited=new WeakSet){if(!api||typeof api!=="object"||visited.has(api)){return 0}visited.add(api);let count=0;for(const[key,value]of Object.entries(api)){if(key.startsWith("__")||key.startsWith("_")){continue}count+=1;if(value&&typeof value==="object"){count+=this._countPaths(value,visited)}}return count}clear(){this.caches.clear();this.slothlet.debug("cache",{key:"DEBUG_MODE_ALL_CACHES_CLEARED"})}async rebuildCache(moduleID){const entry=this.get(moduleID);if(!entry){throw new this.SlothletError("CACHE_NOT_FOUND",{moduleID,operation:"rebuild",validationError:true})}this.slothlet.debug("cache",{key:"DEBUG_MODE_REBUILDING_CACHE_FROM_DISK",moduleID,folderPath:entry.folderPath,mode:entry.mode});const freshApi=await this.slothlet.builders.builder.buildAPI({dir:entry.folderPath,mode:entry.mode,sanitize:entry.sanitizeOptions,moduleID,apiPathPrefix:entry.endpoint==="."?"":entry.endpoint,collisionMode:entry.collisionMode,hidden:entry.hidden??null,scanHiddenFolders:entry.scanHiddenFolders===true,collisionContext:entry.endpoint==="."?"initial":"addApi",cacheBust:Date.now(),...entry.syntheticExports?{syntheticExports:entry.syntheticExports,syntheticName:entry.endpoint?entry.endpoint.split(".").pop():"synthetic"}:{}});this.slothlet.debug("cache",{key:"DEBUG_MODE_CACHE_REBUILT_SUCCESSFULLY",moduleID,timestamp:Date.now()});return freshApi}}export{ApiCacheManager};