@cldmv/slothlet 3.14.0 โ†’ 3.15.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -37,25 +37,25 @@ v3 rebuilds Slothlet from the inside out with a **Unified Wrapper architecture**
37
37
 
38
38
  Every feature has been hardened with a comprehensive test suite - over **5,300 tests** across eager, lazy, CJS, ESM, TypeScript, and mixed module scenarios.
39
39
 
40
- ๐Ÿ“‹ **[See the full v3.0 changelog](./docs/changelog/v3.0.md)** for the architecture rewrite, hook system redesign, i18n layer, background materialization, lifecycle events, collision modes, mutation controls, sanitization improvements, and context isolation upgrades.
40
+ ๐Ÿ“‹ **[See the full v3.0 changelog](https://github.com/CLDMV/slothlet/blob/master/docs/changelog/v3.0.md)** for the architecture rewrite, hook system redesign, i18n layer, background materialization, lifecycle events, collision modes, mutation controls, sanitization improvements, and context isolation upgrades.
41
41
 
42
42
  ---
43
43
 
44
44
  ## โœจ What's New
45
45
 
46
- ### Latest: v3.14.0 (August 2026)
46
+ ### Latest: v3.15.1 (August 2026)
47
47
 
48
- - **Browser importmap resolves consumer-graph package exports (#297)** โ€” `generateBrowserAssets` now emits the exact `exports` subpath keys for the third-party packages your API leaves import, not just `@cldmv/slothlet`'s own surface. Import maps do plain prefix substitution and never consult a package's `exports`, so a redirected subpath (`@scope/ext/errors` โ†’ `./src/lib/errors.mjs`) previously 404'd in the browser and consumers hand-maintained allowlists. The generator now scans the API directory for the packages its leaves import, reads each package's `exports`, and emits the exact redirected keys โ€” flat entries, wildcard directories, and the browser/`import`/`default` condition of conditional exports โ€” served under a base derived from `slothletBase`. A new exported primitive, `collectPackageSpecifiers`, does the package-agnostic collection; `collectSlothletSpecifiers` is unchanged.
49
- - [View full v3.14.0 Changelog](./docs/changelog/v3/v3.14.0.md)
48
+ - **Maintenance & supply-chain hardening โ€” no runtime changes** โ€” The public API and loader behavior are identical to 3.15.0. This release scopes every GitHub Actions workflow token to least privilege (#319), clears two high-severity advisories in the dev-only test/lint toolchain (`brace-expansion`, `nanoid` โ€” transitive, never shipped to consumers; #322), adds an OpenSSF Scorecard badge (#320), and fixes documentation links and CI plumbing (#316, #321, #314).
49
+ - [View full v3.15.1 Changelog](https://github.com/CLDMV/slothlet/blob/master/docs/changelog/v3/v3.15.1.md)
50
50
 
51
51
  ### Recent Releases
52
52
 
53
- - **v3.13.3** (August 2026) โ€” Completes the version-dispatcher permissions fix (a second framework read path probed the marker with a gated `__`-private read) by detecting a dispatcher by object identity, and fixes nested-instance permission isolation so a second `slothlet()` booted inside a permissioned leaf no longer throws during its own construction ([Changelog](./docs/changelog/v3/v3.13.3.md))
54
- - **v3.13.2** (August 2026) โ€” Restores composition of version-dispatched fields under a `permissions` configuration: slothlet's own version-dispatcher marker keys are exempted from the 3.13.0 module-private (`_`/`__`) rule by object identity, so a colliding version-dispatched field no longer fails at composition with `PERMISSION_DENIED` while a consumer's identically-named private member stays denied ([Changelog](./docs/changelog/v3/v3.13.2.md))
55
- - **v3.13.1** (August 2026) โ€” `devcheck` dev-environment detection fix: reads the `--conditions=slothlet-dev` CLI form from `process.execArgv` and recognizes a scoped `node_modules` install at any depth, so a correct dev run or a git/tarball install no longer self-terminates ([Changelog](./docs/changelog/v3/v3.13.1.md))
56
- - **v3.13.0** (August 2026) โ€” Sync/async-transparent hook dispatch, `api.slothlet.api.leaves()` for module-scoped path enumeration, and permission-enforced module-private (`_`/`__`) exports plus an injectable importer that attributes leaf execution in consumer coverage ([Changelog](./docs/changelog/v3/v3.13.0.md))
53
+ - **v3.15.0** (August 2026) โ€” Character-safe `moduleID`s and scoped `remove(moduleID, apiPath)`: a `moduleID` may contain any character and round-trips through `add`/`leaves`/`remove`/`reload`; scoped removals and synthetic adds now survive `reload()`; plus a prototype-pollution guard on mount paths (#303, #302, #304) ([Changelog](https://github.com/CLDMV/slothlet/blob/master/docs/changelog/v3/v3.15.0.md))
54
+ - **v3.14.0** (August 2026) โ€” Browser importmap resolves consumer-graph package `exports` subpaths (not just slothlet's own surface), so a redirected dependency subpath no longer 404s in the browser and consumers can drop hand-maintained allowlists (#297) ([Changelog](https://github.com/CLDMV/slothlet/blob/master/docs/changelog/v3/v3.14.0.md))
55
+ - **v3.13.3** (August 2026) โ€” Completes the version-dispatcher permissions fix (a second framework read path probed the marker with a gated `__`-private read) by detecting a dispatcher by object identity, and fixes nested-instance permission isolation so a second `slothlet()` booted inside a permissioned leaf no longer throws during its own construction ([Changelog](https://github.com/CLDMV/slothlet/blob/master/docs/changelog/v3/v3.13.3.md))
56
+ - **v3.13.2** (August 2026) โ€” Restores composition of version-dispatched fields under a `permissions` configuration: slothlet's own version-dispatcher marker keys are exempted from the 3.13.0 module-private (`_`/`__`) rule by object identity, so a colliding version-dispatched field no longer fails at composition with `PERMISSION_DENIED` while a consumer's identically-named private member stays denied ([Changelog](https://github.com/CLDMV/slothlet/blob/master/docs/changelog/v3/v3.13.2.md))
57
57
 
58
- ๐Ÿ“š **For complete version history and detailed release notes, see [docs/changelog/](./docs/changelog/) folder.**
58
+ ๐Ÿ“š **For complete version history and detailed release notes, see [docs/changelog/](https://github.com/CLDMV/slothlet/tree/master/docs/changelog/) folder.**
59
59
 
60
60
  ---
61
61
 
@@ -80,7 +80,7 @@ Every feature has been hardened with a comprehensive test suite - over **5,300 t
80
80
  - **Zero dependencies**: Pure Node.js implementation
81
81
  - **Memory efficiency**: Lazy mode loads modules on-demand, eager mode optimizes for predictable behavior
82
82
 
83
- ๐Ÿ“Š **For comprehensive performance benchmarks and analysis, see [docs/PERFORMANCE.md](./docs/PERFORMANCE.md)**
83
+ ๐Ÿ“Š **For comprehensive performance benchmarks and analysis, see [docs/PERFORMANCE.md](https://github.com/CLDMV/slothlet/blob/master/docs/PERFORMANCE.md)**
84
84
 
85
85
  ### ๐ŸŽฃ **Hook System** _(redesigned in v3)_
86
86
 
@@ -93,7 +93,7 @@ Powerful function interceptor system with 4 hook types and three-phase subset or
93
93
 
94
94
  Each hook type supports three ordered execution **subsets**: `"before"` โ†’ `"primary"` (default) โ†’ `"after"`. Pattern matching, priority control, runtime enable/disable, and short-circuit support included.
95
95
 
96
- ๐ŸŽฃ **For complete hook system documentation, see [docs/HOOKS.md](./docs/HOOKS.md)**
96
+ ๐ŸŽฃ **For complete hook system documentation, see [docs/HOOKS.md](https://github.com/CLDMV/slothlet/blob/master/docs/HOOKS.md)**
97
97
 
98
98
  ### ๐Ÿ” **Permission System** _(new in v3.3, read-gated in v3.7)_
99
99
 
@@ -107,13 +107,13 @@ Path-based access control for inter-module API calls **and** data-value reads (v
107
107
  - **Runtime management** โ€” `api.slothlet.permissions.addRule()`, `.removeRule()`, `.self.*`, `.global.*`, `.control.*`
108
108
  - **Context conditions** _(v3.4)_ โ€” optional `condition` field; accepts a plain object (deep leaf matching), function, or array (OR); evaluated against per-request ALS context
109
109
 
110
- ๐Ÿ” **For complete permission system documentation, see [docs/PERMISSIONS.md](./docs/PERMISSIONS.md)** ยท ๐Ÿ“ **For condition syntax, see [docs/PERMISSIONS-CONDITIONS.md](./docs/PERMISSIONS-CONDITIONS.md)**
110
+ ๐Ÿ” **For complete permission system documentation, see [docs/PERMISSIONS.md](https://github.com/CLDMV/slothlet/blob/master/docs/PERMISSIONS.md)** ยท ๐Ÿ“ **For condition syntax, see [docs/PERMISSIONS-CONDITIONS.md](https://github.com/CLDMV/slothlet/blob/master/docs/PERMISSIONS-CONDITIONS.md)**
111
111
 
112
112
  ### ๐ŸŒ **Full Internationalization** _(new in v3)_
113
113
 
114
114
  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)
115
115
 
116
- 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)**.
116
+ 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](https://github.com/CLDMV/slothlet/blob/master/docs/I18N.md)**.
117
117
 
118
118
  ### ๐Ÿ”„ **Context Propagation**
119
119
 
@@ -124,7 +124,7 @@ Automatic context preservation across all asynchronous boundaries:
124
124
  - **Class instance propagation**: Context preserved in class method calls
125
125
  - **Zero configuration**: Works automatically with TCP servers, HTTP servers, and custom EventEmitters
126
126
 
127
- ๐Ÿ”„ **For context propagation details, see [docs/CONTEXT-PROPAGATION.md](./docs/CONTEXT-PROPAGATION.md)**
127
+ ๐Ÿ”„ **For context propagation details, see [docs/CONTEXT-PROPAGATION.md](https://github.com/CLDMV/slothlet/blob/master/docs/CONTEXT-PROPAGATION.md)**
128
128
 
129
129
  ### ๐Ÿ”ง **Smart API Management**
130
130
 
@@ -133,7 +133,7 @@ Automatic context preservation across all asynchronous boundaries:
133
133
  - **Advanced Sanitization**: Custom naming rules with glob and boundary patterns; `api.slothlet.sanitize()` at runtime
134
134
  - **Hybrid Exports**: Support for callable APIs with methods, default + named exports
135
135
 
136
- ๐Ÿ—๏ธ **[Module structure](./docs/MODULE-STRUCTURE.md)** ยท ๐Ÿ“ **[API flattening](./docs/API-RULES/API-FLATTENING.md)** ยท ๐Ÿ”ก **[Sanitization](./docs/SANITIZATION.md)**
136
+ ๐Ÿ—๏ธ **[Module structure](https://github.com/CLDMV/slothlet/blob/master/docs/MODULE-STRUCTURE.md)** ยท ๐Ÿ“ **[API flattening](https://github.com/CLDMV/slothlet/blob/master/docs/API-RULES/API-FLATTENING.md)** ยท ๐Ÿ”ก **[Sanitization](https://github.com/CLDMV/slothlet/blob/master/docs/SANITIZATION.md)**
137
137
 
138
138
  ### ๐Ÿ”— **Runtime & Context System**
139
139
 
@@ -151,11 +151,11 @@ Run slothlet in the browser, web workers, and Electron renderers โ€” anywhere th
151
151
  - **Bundler-friendly**: bundled apps need only the manifest; raw-ESM pages and Electron renderers get the importmap too
152
152
  - **Full parity**: `self`, hooks, permissions, metadata, i18n, lifecycle events, and api mutation all work in-browser (live-binding context manager)
153
153
 
154
- ๐ŸŒ **For complete browser-mode documentation, see [docs/BROWSER.md](./docs/BROWSER.md)**
154
+ ๐ŸŒ **For complete browser-mode documentation, see [docs/BROWSER.md](https://github.com/CLDMV/slothlet/blob/master/docs/BROWSER.md)**
155
155
 
156
156
  ### ๐Ÿ›  **Developer Experience**
157
157
 
158
- - **TypeScript-Friendly**: Comprehensive JSDoc annotations with auto-generated declarations โ€” see **[docs/TYPESCRIPT.md](./docs/TYPESCRIPT.md)**
158
+ - **TypeScript-Friendly**: Comprehensive JSDoc annotations with auto-generated declarations โ€” see **[docs/TYPESCRIPT.md](https://github.com/CLDMV/slothlet/blob/master/docs/TYPESCRIPT.md)**
159
159
  - **Configurable Debug**: Detailed logging via CLI flags or environment variables
160
160
  - **Multiple Instances**: Parameter-based isolation for complex applications
161
161
  - **Inspectable APIs**: `console.log(api.math)` and logical versioned paths like `console.log(api.auth)` show real module contents instead of proxy internals (v3+)
@@ -207,19 +207,19 @@ const result = await api.math.add(2, 3); // ALL calls awaited in lazy mode
207
207
 
208
208
  ## ๐Ÿ“š Configuration
209
209
 
210
- The most-used options are summarized below. The complete reference โ€” every option, every diagnostic, every deprecated alias โ€” lives in **[docs/CONFIGURATION.md](./docs/CONFIGURATION.md)**.
210
+ The most-used options are summarized below. The complete reference โ€” every option, every diagnostic, every deprecated alias โ€” lives in **[docs/CONFIGURATION.md](https://github.com/CLDMV/slothlet/blob/master/docs/CONFIGURATION.md)**.
211
211
 
212
- | Option | Type | Default | Description |
213
- | ------------- | -------- | ----------- | ---------------------------------------------------------------------------------- |
214
- | `dir` | `string` | `"api"` | Directory to load API modules from |
215
- | `mode` | `string` | `"eager"` | `"eager"` (load upfront) or `"lazy"` (on-demand with copy-left materialization) |
216
- | `runtime` | `string` | `"async"` | `"async"` (AsyncLocalStorage) or `"live"` (live-bindings) |
217
- | `context` | `object` | `{}` | Per-request context โ€” read via `import { context } from "@cldmv/slothlet/runtime"` |
218
- | `hook` | `mixed` | `false` | Enable hooks; see **[HOOKS.md](./docs/HOOKS.md)** |
219
- | `permissions` | `object` | `undefined` | Path-based access control; see **[PERMISSIONS.md](./docs/PERMISSIONS.md)** |
220
- | `i18n` | `object` | `{}` | Language for translated error/debug messages โ€” see **[I18N.md](./docs/I18N.md)** |
212
+ | Option | Type | Default | Description |
213
+ | ------------- | -------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------- |
214
+ | `dir` | `string` | `"api"` | Directory to load API modules from |
215
+ | `mode` | `string` | `"eager"` | `"eager"` (load upfront) or `"lazy"` (on-demand with copy-left materialization) |
216
+ | `runtime` | `string` | `"async"` | `"async"` (AsyncLocalStorage) or `"live"` (live-bindings) |
217
+ | `context` | `object` | `{}` | Per-request context โ€” read via `import { context } from "@cldmv/slothlet/runtime"` |
218
+ | `hook` | `mixed` | `false` | Enable hooks; see **[HOOKS.md](https://github.com/CLDMV/slothlet/blob/master/docs/HOOKS.md)** |
219
+ | `permissions` | `object` | `undefined` | Path-based access control; see **[PERMISSIONS.md](https://github.com/CLDMV/slothlet/blob/master/docs/PERMISSIONS.md)** |
220
+ | `i18n` | `object` | `{}` | Language for translated error/debug messages โ€” see **[I18N.md](https://github.com/CLDMV/slothlet/blob/master/docs/I18N.md)** |
221
221
 
222
- 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)**.
222
+ 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](https://github.com/CLDMV/slothlet/blob/master/docs/CONFIGURATION.md)**.
223
223
 
224
224
  ---
225
225
 
@@ -238,7 +238,7 @@ api.slothlet.lifecycle.on("materialized:complete", ({ total }) => console.log(`$
238
238
  await api.slothlet.materialize.wait(); // optional: gate traffic on ready
239
239
  ```
240
240
 
241
- ๐Ÿ“Š **Benchmarks & analysis: [docs/PERFORMANCE.md](./docs/PERFORMANCE.md)** ยท ๐Ÿ”€ **Visual pipeline diagram: [docs/MODULE-STRUCTURE.md#loading-pipeline-overview](./docs/MODULE-STRUCTURE.md#loading-pipeline-overview)** ยท โšก **Lifecycle events: [docs/LIFECYCLE.md](./docs/LIFECYCLE.md)**
241
+ ๐Ÿ“Š **Benchmarks & analysis: [docs/PERFORMANCE.md](https://github.com/CLDMV/slothlet/blob/master/docs/PERFORMANCE.md)** ยท ๐Ÿ”€ **Visual pipeline diagram: [docs/MODULE-STRUCTURE.md#loading-pipeline-overview](https://github.com/CLDMV/slothlet/blob/master/docs/MODULE-STRUCTURE.md#loading-pipeline-overview)** ยท โšก **Lifecycle events: [docs/LIFECYCLE.md](https://github.com/CLDMV/slothlet/blob/master/docs/LIFECYCLE.md)**
242
242
 
243
243
  ---
244
244
 
@@ -257,7 +257,7 @@ api.slothlet.hook.on("**:error", ({ path, error, source }) => console.error(path
257
257
  const out = await api.math.add(2, 3); // hooks fire automatically
258
258
  ```
259
259
 
260
- ๐ŸŽฃ **Configuration, all four types, subsets, pattern syntax, management API: [docs/HOOKS.md](./docs/HOOKS.md)**
260
+ ๐ŸŽฃ **Configuration, all four types, subsets, pattern syntax, management API: [docs/HOOKS.md](https://github.com/CLDMV/slothlet/blob/master/docs/HOOKS.md)**
261
261
 
262
262
  ---
263
263
 
@@ -277,7 +277,7 @@ await scoped.database.query();
277
277
 
278
278
  Context propagates automatically through `EventEmitter` callbacks (TCP/HTTP servers, custom emitters), class methods, and every async boundary. Inside modules: `import { context, instanceID } from "@cldmv/slothlet/runtime"`.
279
279
 
280
- ๐Ÿ”„ **Full reference, isolation guarantees, merge strategies, TCP/HTTP examples: [docs/CONTEXT-PROPAGATION.md](./docs/CONTEXT-PROPAGATION.md)**
280
+ ๐Ÿ”„ **Full reference, isolation guarantees, merge strategies, TCP/HTTP examples: [docs/CONTEXT-PROPAGATION.md](https://github.com/CLDMV/slothlet/blob/master/docs/CONTEXT-PROPAGATION.md)**
281
281
 
282
282
  ---
283
283
 
@@ -292,7 +292,7 @@ await api.slothlet.api.reload("database.*"); // hot-reload
292
292
 
293
293
  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).
294
294
 
295
- ๐Ÿ” **Full reference: [docs/RELOAD.md](./docs/RELOAD.md)** ยท ๐Ÿท๏ธ **Metadata system: [docs/METADATA.md](./docs/METADATA.md)**
295
+ ๐Ÿ” **Full reference: [docs/RELOAD.md](https://github.com/CLDMV/slothlet/blob/master/docs/RELOAD.md)** ยท ๐Ÿท๏ธ **Metadata system: [docs/METADATA.md](https://github.com/CLDMV/slothlet/blob/master/docs/METADATA.md)**
296
296
 
297
297
  ---
298
298
 
@@ -313,7 +313,7 @@ api.slothlet.lifecycle.on("impl:removed", ({ apiPath }) => {
313
313
 
314
314
  Events: `materialized:complete`, `impl:created`, `impl:changed`, `impl:removed`. Public surface is `on` / `off` only.
315
315
 
316
- โšก **Full reference: [docs/LIFECYCLE.md](./docs/LIFECYCLE.md)**
316
+ โšก **Full reference: [docs/LIFECYCLE.md](https://github.com/CLDMV/slothlet/blob/master/docs/LIFECYCLE.md)**
317
317
 
318
318
  ---
319
319
 
@@ -351,7 +351,7 @@ export const myModule = {
351
351
 
352
352
  The same import works from `.mjs`, `.cjs` (via `require`), `.ts`, and `.mts` (TypeScript path fixed in v3.5.0).
353
353
 
354
- ๐Ÿ—๏ธ **[Module structure patterns](./docs/MODULE-STRUCTURE.md)** ยท ๐Ÿ“ **[All 13 API transformation rules](./docs/API-RULES.md)**
354
+ ๐Ÿ—๏ธ **[Module structure patterns](https://github.com/CLDMV/slothlet/blob/master/docs/MODULE-STRUCTURE.md)** ยท ๐Ÿ“ **[All 13 API transformation rules](https://github.com/CLDMV/slothlet/blob/master/docs/API-RULES.md)**
355
355
 
356
356
  ---
357
357
 
@@ -387,33 +387,33 @@ try {
387
387
 
388
388
  ### Reference
389
389
 
390
- - **[Configuration Reference](./docs/CONFIGURATION.md)** โ€” every option with defaults, validation rules, and the `api.slothlet.diag.*` namespace
391
- - **[Generated API Reference](./docs/generated/API.md)** โ€” auto-generated from JSDoc; the complete public surface
392
- - **[Changelog](./docs/changelog/)** โ€” all release notes (v2 + v3)
393
- - **[Migration Guide](./docs/MIGRATION.md)** โ€” upgrading from v2.x
390
+ - **[Configuration Reference](https://github.com/CLDMV/slothlet/blob/master/docs/CONFIGURATION.md)** โ€” every option with defaults, validation rules, and the `api.slothlet.diag.*` namespace
391
+ - **[Generated API Reference](https://github.com/CLDMV/slothlet/blob/master/docs/generated/API.md)** โ€” auto-generated from JSDoc; the complete public surface
392
+ - **[Changelog](https://github.com/CLDMV/slothlet/tree/master/docs/changelog/)** โ€” all release notes (v2 + v3)
393
+ - **[Migration Guide](https://github.com/CLDMV/slothlet/blob/master/docs/MIGRATION.md)** โ€” upgrading from v2.x
394
394
 
395
395
  ### Technical Guides
396
396
 
397
- - **[Performance Analysis](./docs/PERFORMANCE.md)** โ€” startup vs runtime benchmarks, memory analysis, materialization cost breakdown
398
- - **[Hook System](./docs/HOOKS.md)** โ€” 4 types, three-phase subsets, pattern matching, management API
399
- - **[Permission System](./docs/PERMISSIONS.md)** โ€” rules, glob patterns, self-call bypass, read gating, runtime management
400
- - **[Permission Conditions](./docs/PERMISSIONS-CONDITIONS.md)** โ€” `condition` field syntax: deep object matching, functions, OR arrays
401
- - **[Context Propagation](./docs/CONTEXT-PROPAGATION.md)** โ€” per-request isolation, EventEmitter / class propagation, merge strategies
402
- - **[Lifecycle Events](./docs/LIFECYCLE.md)** โ€” `materialized:complete`, `impl:*` events, subscription API
403
- - **[Hot Reload & Dynamic API](./docs/RELOAD.md)** โ€” `add`, `remove`, `reload`, collision modes, mutation controls, eager vs lazy semantics
404
- - **[Versioning](./docs/VERSIONING.md)** โ€” multi-version module dispatch, `versionDispatcher`, version metadata
405
- - **[Metadata System](./docs/METADATA.md)** โ€” function metadata tagging for security, authorization, auditing
406
- - **[Module Structure](./docs/MODULE-STRUCTURE.md)** โ€” organization patterns, examples, and the loading-pipeline diagram
407
- - **[Sanitization](./docs/SANITIZATION.md)** โ€” filename โ†’ property-name transformation rules
408
- - **[TypeScript Support](./docs/TYPESCRIPT.md)** โ€” fast mode (esbuild), strict mode (tsc), `.d.ts` generation
409
- - **[Internationalization](./docs/I18N.md)** โ€” supported languages and configuration
410
- - **[Testing & Coverage](./docs/TESTING.md)** โ€” measuring coverage of composition-loaded leaves in a consumer project (the `server.deps.inline` requirement)
397
+ - **[Performance Analysis](https://github.com/CLDMV/slothlet/blob/master/docs/PERFORMANCE.md)** โ€” startup vs runtime benchmarks, memory analysis, materialization cost breakdown
398
+ - **[Hook System](https://github.com/CLDMV/slothlet/blob/master/docs/HOOKS.md)** โ€” 4 types, three-phase subsets, pattern matching, management API
399
+ - **[Permission System](https://github.com/CLDMV/slothlet/blob/master/docs/PERMISSIONS.md)** โ€” rules, glob patterns, self-call bypass, read gating, runtime management
400
+ - **[Permission Conditions](https://github.com/CLDMV/slothlet/blob/master/docs/PERMISSIONS-CONDITIONS.md)** โ€” `condition` field syntax: deep object matching, functions, OR arrays
401
+ - **[Context Propagation](https://github.com/CLDMV/slothlet/blob/master/docs/CONTEXT-PROPAGATION.md)** โ€” per-request isolation, EventEmitter / class propagation, merge strategies
402
+ - **[Lifecycle Events](https://github.com/CLDMV/slothlet/blob/master/docs/LIFECYCLE.md)** โ€” `materialized:complete`, `impl:*` events, subscription API
403
+ - **[Hot Reload & Dynamic API](https://github.com/CLDMV/slothlet/blob/master/docs/RELOAD.md)** โ€” `add`, `remove`, `reload`, collision modes, mutation controls, eager vs lazy semantics
404
+ - **[Versioning](https://github.com/CLDMV/slothlet/blob/master/docs/VERSIONING.md)** โ€” multi-version module dispatch, `versionDispatcher`, version metadata
405
+ - **[Metadata System](https://github.com/CLDMV/slothlet/blob/master/docs/METADATA.md)** โ€” function metadata tagging for security, authorization, auditing
406
+ - **[Module Structure](https://github.com/CLDMV/slothlet/blob/master/docs/MODULE-STRUCTURE.md)** โ€” organization patterns, examples, and the loading-pipeline diagram
407
+ - **[Sanitization](https://github.com/CLDMV/slothlet/blob/master/docs/SANITIZATION.md)** โ€” filename โ†’ property-name transformation rules
408
+ - **[TypeScript Support](https://github.com/CLDMV/slothlet/blob/master/docs/TYPESCRIPT.md)** โ€” fast mode (esbuild), strict mode (tsc), `.d.ts` generation
409
+ - **[Internationalization](https://github.com/CLDMV/slothlet/blob/master/docs/I18N.md)** โ€” supported languages and configuration
410
+ - **[Testing & Coverage](https://github.com/CLDMV/slothlet/blob/master/docs/TESTING.md)** โ€” measuring coverage of composition-loaded leaves in a consumer project (the `server.deps.inline` requirement)
411
411
 
412
412
  ### API Rules & Transformation
413
413
 
414
- - **[API Rules](./docs/API-RULES.md)** โ€” all 13 transformation rules with verified test examples
415
- - **[API Rules Conditions](./docs/API-RULES/API-RULES-CONDITIONS.md)** โ€” every conditional that controls API generation
416
- - **[API Flattening](./docs/API-RULES/API-FLATTENING.md)** โ€” flattening rules with decision tree
414
+ - **[API Rules](https://github.com/CLDMV/slothlet/blob/master/docs/API-RULES.md)** โ€” all 13 transformation rules with verified test examples
415
+ - **[API Rules Conditions](https://github.com/CLDMV/slothlet/blob/master/docs/API-RULES/API-RULES-CONDITIONS.md)** โ€” every conditional that controls API generation
416
+ - **[API Flattening](https://github.com/CLDMV/slothlet/blob/master/docs/API-RULES/API-FLATTENING.md)** โ€” flattening rules with decision tree
417
417
 
418
418
  ### Repo
419
419
 
@@ -422,7 +422,7 @@ try {
422
422
  - **[Security Policy](./SECURITY.md)** โ€” security guidelines and reporting
423
423
  - **[Test Documentation](./api_tests/)** โ€” comprehensive test module examples
424
424
 
425
- [![CodeFactor]][codefactor_url] [![npms.io score]][npms_url] [![npm unpacked size]][npm_size_url] [![Repo size]][repo_size_url]
425
+ [![CodeFactor]][codefactor_url] [![OpenSSF Scorecard]][ossf_scorecard_url] [![npms.io score]][npms_url] [![npm unpacked size]][npm_size_url] [![Repo size]][repo_size_url]
426
426
 
427
427
  ---
428
428
 
@@ -466,6 +466,8 @@ To my wife and children - thank you for your patience, your encouragement, and t
466
466
  [npm_last_update_url]: https://www.npmjs.com/package/@cldmv/slothlet
467
467
  [codefactor]: https://img.shields.io/codefactor/grade/github/CLDMV/slothlet?style=for-the-badge&logo=codefactor&logoColor=white&labelColor=F44A6A
468
468
  [codefactor_url]: https://www.codefactor.io/repository/github/cldmv/slothlet
469
+ [openssf scorecard]: https://img.shields.io/ossf-scorecard/github.com/CLDMV/slothlet?style=for-the-badge&label=OpenSSF%20Scorecard
470
+ [ossf_scorecard_url]: https://scorecard.dev/viewer/?uri=github.com/CLDMV/slothlet
469
471
  [npms.io score]: https://img.shields.io/npms-io/final-score/%40cldmv%2Fslothlet?style=for-the-badge&logo=npms&logoColor=white&labelColor=0B5D57
470
472
  [npms_url]: https://npms.io/search?q=%40cldmv%2Fslothlet
471
473
  [npm downloads]: https://img.shields.io/npm/dm/%40cldmv%2Fslothlet.svg?style=for-the-badge&logo=npm&logoColor=white&labelColor=CB3837
@@ -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"#factories/component-base";import{TYPE_STATES}from"#handlers/unified-wrapper";import{TRUSTED_ROOT,PROTECT_SENTINEL}from"#handlers/trusted-root";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 describeScopeReceived(value){if(Array.isArray(value)){const badIndex=value.findIndex(entry=>typeof entry!=="string");if(badIndex!==-1){return`array with non-string entry (${typeof value[badIndex]} at index ${badIndex})`}return"array"}return typeof value}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){if(!this.____config?.silent){new this.SlothletWarning("WARNING_RESERVED_PROPERTY_CONFLICT",{properties:"slothlet"})}await this.emitImplDiagnostic("warning",{apiPath:"slothlet",code:"WARNING_RESERVED_PROPERTY_CONFLICT",context:{properties:"slothlet"},source:"buildAPI"})}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?.(slothlet.instanceID);const identity=slothlet.contextManager?.getCallerIdentity?.(slothlet.instanceID);if(identity?.unresolved){throw new slothlet.SlothletError("PERMISSION_DENIED",{caller:null,target:targetPath})}const callerWrapper=identity?.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?.(slothlet.instanceID);const identity=slothlet.contextManager?.getCallerIdentity?.(slothlet.instanceID);if(identity?.unresolved)return false;const callerWrapper=identity?.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)},leaves:async function slothlet_api_leaves(key,options={}){enforceInternalPermission("slothlet.api.leaves");if(typeof key!=="string"){throw new slothlet.SlothletError("INVALID_ARGUMENT",{argument:"key",expected:"string",received:typeof key,validationError:true})}const normalizedOptions=options==null?{}:options;if(typeof normalizedOptions!=="object"||Array.isArray(normalizedOptions)){throw new slothlet.SlothletError("INVALID_ARGUMENT",{argument:"options",expected:"object with optional boolean details/includePrivate",received:Array.isArray(normalizedOptions)?"array":typeof normalizedOptions,validationError:true})}const{details=false,includePrivate=false}=normalizedOptions;for(const[name,value]of[["details",details],["includePrivate",includePrivate]]){if(typeof value!=="boolean"){throw new slothlet.SlothletError("INVALID_ARGUMENT",{argument:`options.${name}`,expected:"boolean",received:typeof value,validationError:true})}}const ownership=slothlet.handlers.ownership;const leavesIdentity=slothlet.contextManager?.getCallerIdentity?.();const leavesCaller=leavesIdentity?.currentWrapper??null;if(includePrivate&&leavesCaller){throw new slothlet.SlothletError("PERMISSION_DENIED",{caller:leavesCaller.____slothletInternal?.apiPath??"",target:"slothlet.api.leaves:includePrivate"})}let moduleID=null;if(key==="."||key===""){moduleID=[...ownership.moduleEndpoints.entries()].find(([,endpoint2])=>endpoint2===".")?.[0]}else if(ownership.moduleToPath.has(key)){moduleID=key}else{moduleID=ownership.getCurrentOwner(key)?.moduleID??null;if(!moduleID){moduleID=[...ownership.moduleEndpoints.entries()].find(([,endpoint2])=>endpoint2===key)?.[0]??null}}if(!moduleID||!ownership.moduleToPath.has(moduleID)){throw new slothlet.SlothletError("API_LEAVES_UNKNOWN_MODULE",{key},null,{validationError:true})}const endpoint=ownership.moduleEndpoints.get(moduleID);const boundApi=slothlet.boundApi;if(config.mode==="lazy"&&boundApi){const seen=new WeakSet;let root=boundApi;if(endpoint!=="."){for(const segment of endpoint.split("."))root=root[segment]}const pending=[{node:root,path:endpoint==="."?"":endpoint}];while(pending.length>0){const{node,path}=pending.pop();if(node===null||typeof node!=="object"&&typeof node!=="function")continue;if(seen.has(node))continue;seen.add(node);if(typeof node._materialize==="function"&&node.__materialized===false){await node._materialize()}const childKeys=new Set(Object.keys(node));const records=ownership.moduleToPath.get(moduleID);if(path!==null&&records){const prefix=path===""?"":`${path}.`;for(const ownedPath of records){if(ownedPath===""||prefix!==""&&!ownedPath.startsWith(prefix))continue;const rest=ownedPath.slice(prefix.length);const segmentEnd=rest.indexOf(".");childKeys.add(segmentEnd===-1?rest:rest.slice(0,segmentEnd))}}for(const childKey of childKeys){if(path===""&&(childKey==="slothlet"||childKey==="shutdown"||childKey==="destroy"))continue;let child;try{child=node[childKey]}catch{continue}const childPath=path===null?null:path===""?childKey:`${path}.${childKey}`;pending.push({node:child,path:records?.has(childPath)?childPath:null})}}}if(!ownership.moduleToPath.has(moduleID)){throw new slothlet.SlothletError("API_LEAVES_UNKNOWN_MODULE",{key},null,{validationError:true})}const ownedPaths=[...ownership.moduleToPath.get(moduleID)].filter(path=>{if(path==="")return false;if(endpoint==="."&&(path==="slothlet"||path.startsWith("slothlet.")||path==="shutdown"||path==="destroy"))return false;const currentOwner=ownership.getCurrentOwner(path);return!currentOwner||currentOwner.moduleID===moduleID});ownedPaths.sort();const namespaces=new Set;for(const owned of ownedPaths){let cut=owned.lastIndexOf(".");while(cut>0){namespaces.add(owned.slice(0,cut));cut=owned.lastIndexOf(".",cut-1)}}const kindOf=path=>{if(namespaces.has(path))return"namespace";const entry=ownership.pathToModule.get(path)?.find(candidate=>candidate.moduleID===moduleID);return typeof entry?.value==="function"?"function":"data"};const permissionManager=slothlet.handlers?.permissionManager;let visiblePaths=ownedPaths;if(!includePrivate&&permissionManager?.isEnabled?.()){const callerPath=leavesCaller?.____slothletInternal?.apiPath??"";const callerFilePath=leavesCaller?.____slothletInternal?.filePath??null;const runtimeContext=slothlet.contextManager?.tryGetContext?.()?.context??null;visiblePaths=ownedPaths.filter(path=>{if(!permissionManager.isPrivateTarget(path))return true;const entry=ownership.pathToModule.get(path)?.find(candidate=>candidate.moduleID===moduleID);return permissionManager.checkAccess(callerPath,path,callerFilePath,entry?.filePath,runtimeContext)})}if(details){return visiblePaths.map(path=>({path,kind:kindOf(path)}))}return visiblePaths.filter(path=>kindOf(path)==="function")},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?.getCallerIdentity?.()?.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 currentWrapper=slothlet.contextManager?.getCallerIdentity?.()?.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=slothlet.contextManager?.getCallerIdentity?.()?.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?.getCallerIdentity?.()?.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)},seal:function slothlet_permissions_control_seal(){const permissionManager=slothlet.handlers?.permissionManager;if(!permissionManager?.seal){throw new slothlet.SlothletError("PERMISSION_MANAGER_NOT_AVAILABLE",{validationError:true})}slothlet.handlers.permissionManager.seal()},get sealed(){const permissionManager=slothlet.handlers?.permissionManager;if(!permissionManager?.isSealed){throw new slothlet.SlothletError("PERMISSION_MANAGER_NOT_AVAILABLE",{validationError:true})}return permissionManager.isSealed()}}}};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.config.collectLifecycleHooks){const nestedHooks=(await slothlet._collectLifecycleHooks("shutdown")).reverse();for(const{fn,receiver}of nestedHooks){try{await Reflect.apply(fn,receiver,[])}catch{}}}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,protect,owners}=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})}if(protect!==void 0&&(!Array.isArray(protect)||protect.some(k=>typeof k!=="string"))){throw new slothlet.SlothletError("SCOPE_INVALID_PROTECT",{received:describeScopeReceived(protect)},null,{validationError:true})}if(owners!==void 0){if(typeof owners!=="object"||owners===null||Array.isArray(owners)){throw new slothlet.SlothletError("SCOPE_INVALID_OWNERS",{received:describeScopeReceived(owners)},null,{validationError:true})}for(const[key,owner]of Object.entries(owners)){if(typeof owner!=="string"||owner.length===0){throw new slothlet.SlothletError("INVALID_ARGUMENT",{argument:`owners.${key}`,expected:"non-empty string",received:typeof owner==="string"?"empty string":typeof owner,validationError:true})}}}const buildContextOwners=parentOwners=>{const base=parentOwners??null;let child=base;const claim=(key,owner)=>{const existing=child&&Object.prototype.hasOwnProperty.call(child,key)?child[key]:void 0;if(existing!==void 0&&existing!==owner){throw new slothlet.SlothletError("CONTEXT_KEY_OWNED",{key:String(key)},null,{validationError:true})}if(child===base)child=base?Object.assign(Object.create(null),base):Object.create(null);child[key]=owner};if(Array.isArray(protect))for(const k of protect)claim(k,PROTECT_SENTINEL);if(owners&&typeof owners==="object")for(const[k,o]of Object.entries(owners))claim(k,o);return child};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,__contextOwners:buildContextOwners(currentStore.__contextOwners)};if(currentStore[TRUSTED_ROOT]===true){Object.defineProperty(childStore,TRUSTED_ROOT,{value:true,configurable:true})}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,__contextOwners:buildContextOwners(currentStore.__contextOwners)};if(currentStore[TRUSTED_ROOT]===true){Object.defineProperty(childStore,TRUSTED_ROOT,{value:true,configurable:true})}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.config.collectLifecycleHooks){const nestedHooks=(await slothlet._collectLifecycleHooks("destroy")).reverse();for(const{fn,receiver}of nestedHooks){try{await Reflect.apply(fn,receiver,[])}catch{}}}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"#factories/component-base";import{TYPE_STATES}from"#handlers/unified-wrapper";import{TRUSTED_ROOT,PROTECT_SENTINEL}from"#handlers/trusted-root";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 describeScopeReceived(value){if(Array.isArray(value)){const badIndex=value.findIndex(entry=>typeof entry!=="string");if(badIndex!==-1){return`array with non-string entry (${typeof value[badIndex]} at index ${badIndex})`}return"array"}return typeof value}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){if(!this.____config?.silent){new this.SlothletWarning("WARNING_RESERVED_PROPERTY_CONFLICT",{properties:"slothlet"})}await this.emitImplDiagnostic("warning",{apiPath:"slothlet",code:"WARNING_RESERVED_PROPERTY_CONFLICT",context:{properties:"slothlet"},source:"buildAPI"})}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?.(slothlet.instanceID);const identity=slothlet.contextManager?.getCallerIdentity?.(slothlet.instanceID);if(identity?.unresolved){throw new slothlet.SlothletError("PERMISSION_DENIED",{caller:null,target:targetPath})}const callerWrapper=identity?.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?.(slothlet.instanceID);const identity=slothlet.contextManager?.getCallerIdentity?.(slothlet.instanceID);if(identity?.unresolved)return false;const callerWrapper=identity?.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,apiPath){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})}if(apiPath!==void 0&&typeof apiPath!=="string"){throw new slothlet.SlothletError("INVALID_ARGUMENT",{argument:"apiPath",expected:"string",received:typeof apiPath,validationError:true})}return slothlet.handlers.apiManager.removeApiComponent(pathOrModuleId,{scopedApiPath:apiPath})},leaves:async function slothlet_api_leaves(key,options={}){enforceInternalPermission("slothlet.api.leaves");if(typeof key!=="string"){throw new slothlet.SlothletError("INVALID_ARGUMENT",{argument:"key",expected:"string",received:typeof key,validationError:true})}const normalizedOptions=options==null?{}:options;if(typeof normalizedOptions!=="object"||Array.isArray(normalizedOptions)){throw new slothlet.SlothletError("INVALID_ARGUMENT",{argument:"options",expected:"object with optional boolean details/includePrivate",received:Array.isArray(normalizedOptions)?"array":typeof normalizedOptions,validationError:true})}const{details=false,includePrivate=false}=normalizedOptions;for(const[name,value]of[["details",details],["includePrivate",includePrivate]]){if(typeof value!=="boolean"){throw new slothlet.SlothletError("INVALID_ARGUMENT",{argument:`options.${name}`,expected:"boolean",received:typeof value,validationError:true})}}const ownership=slothlet.handlers.ownership;const leavesIdentity=slothlet.contextManager?.getCallerIdentity?.();const leavesCaller=leavesIdentity?.currentWrapper??null;if(includePrivate&&leavesCaller){throw new slothlet.SlothletError("PERMISSION_DENIED",{caller:leavesCaller.____slothletInternal?.apiPath??"",target:"slothlet.api.leaves:includePrivate"})}let moduleID=null;if(key==="."||key===""){moduleID=[...ownership.moduleEndpoints.entries()].find(([,endpoint2])=>endpoint2===".")?.[0]}else if(ownership.moduleToPath.has(key)){moduleID=key}else{moduleID=ownership.getCurrentOwner(key)?.moduleID??null;if(!moduleID){moduleID=[...ownership.moduleEndpoints.entries()].find(([,endpoint2])=>endpoint2===key)?.[0]??null}}if(!moduleID||!ownership.moduleToPath.has(moduleID)){throw new slothlet.SlothletError("API_LEAVES_UNKNOWN_MODULE",{key},null,{validationError:true})}const endpoint=ownership.moduleEndpoints.get(moduleID);const boundApi=slothlet.boundApi;if(config.mode==="lazy"&&boundApi){const seen=new WeakSet;let root=boundApi;if(endpoint!=="."){for(const segment of endpoint.split("."))root=root[segment]}const pending=[{node:root,path:endpoint==="."?"":endpoint}];while(pending.length>0){const{node,path}=pending.pop();if(node===null||typeof node!=="object"&&typeof node!=="function")continue;if(seen.has(node))continue;seen.add(node);if(typeof node._materialize==="function"&&node.__materialized===false){await node._materialize()}const childKeys=new Set(Object.keys(node));const records=ownership.moduleToPath.get(moduleID);if(path!==null&&records){const prefix=path===""?"":`${path}.`;for(const ownedPath of records){if(ownedPath===""||prefix!==""&&!ownedPath.startsWith(prefix))continue;const rest=ownedPath.slice(prefix.length);const segmentEnd=rest.indexOf(".");childKeys.add(segmentEnd===-1?rest:rest.slice(0,segmentEnd))}}for(const childKey of childKeys){if(path===""&&(childKey==="slothlet"||childKey==="shutdown"||childKey==="destroy"))continue;let child;try{child=node[childKey]}catch{continue}const childPath=path===null?null:path===""?childKey:`${path}.${childKey}`;pending.push({node:child,path:records?.has(childPath)?childPath:null})}}}if(!ownership.moduleToPath.has(moduleID)){throw new slothlet.SlothletError("API_LEAVES_UNKNOWN_MODULE",{key},null,{validationError:true})}const ownedPaths=[...ownership.moduleToPath.get(moduleID)].filter(path=>{if(path==="")return false;if(endpoint==="."&&(path==="slothlet"||path.startsWith("slothlet.")||path==="shutdown"||path==="destroy"))return false;const currentOwner=ownership.getCurrentOwner(path);return!currentOwner||currentOwner.moduleID===moduleID});ownedPaths.sort();const namespaces=new Set;for(const owned of ownedPaths){let cut=owned.lastIndexOf(".");while(cut>0){namespaces.add(owned.slice(0,cut));cut=owned.lastIndexOf(".",cut-1)}}const kindOf=path=>{if(namespaces.has(path))return"namespace";const entry=ownership.pathToModule.get(path)?.find(candidate=>candidate.moduleID===moduleID);return typeof entry?.value==="function"?"function":"data"};const permissionManager=slothlet.handlers?.permissionManager;let visiblePaths=ownedPaths;if(!includePrivate&&permissionManager?.isEnabled?.()){const callerPath=leavesCaller?.____slothletInternal?.apiPath??"";const callerFilePath=leavesCaller?.____slothletInternal?.filePath??null;const runtimeContext=slothlet.contextManager?.tryGetContext?.()?.context??null;visiblePaths=ownedPaths.filter(path=>{if(!permissionManager.isPrivateTarget(path))return true;const entry=ownership.pathToModule.get(path)?.find(candidate=>candidate.moduleID===moduleID);return permissionManager.checkAccess(callerPath,path,callerFilePath,entry?.filePath,runtimeContext)})}if(details){return visiblePaths.map(path=>({path,kind:kindOf(path)}))}return visiblePaths.filter(path=>kindOf(path)==="function")},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?.getCallerIdentity?.()?.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 currentWrapper=slothlet.contextManager?.getCallerIdentity?.()?.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=slothlet.contextManager?.getCallerIdentity?.()?.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?.getCallerIdentity?.()?.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)},seal:function slothlet_permissions_control_seal(){const permissionManager=slothlet.handlers?.permissionManager;if(!permissionManager?.seal){throw new slothlet.SlothletError("PERMISSION_MANAGER_NOT_AVAILABLE",{validationError:true})}slothlet.handlers.permissionManager.seal()},get sealed(){const permissionManager=slothlet.handlers?.permissionManager;if(!permissionManager?.isSealed){throw new slothlet.SlothletError("PERMISSION_MANAGER_NOT_AVAILABLE",{validationError:true})}return permissionManager.isSealed()}}}};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.config.collectLifecycleHooks){const nestedHooks=(await slothlet._collectLifecycleHooks("shutdown")).reverse();for(const{fn,receiver}of nestedHooks){try{await Reflect.apply(fn,receiver,[])}catch{}}}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,protect,owners}=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})}if(protect!==void 0&&(!Array.isArray(protect)||protect.some(k=>typeof k!=="string"))){throw new slothlet.SlothletError("SCOPE_INVALID_PROTECT",{received:describeScopeReceived(protect)},null,{validationError:true})}if(owners!==void 0){if(typeof owners!=="object"||owners===null||Array.isArray(owners)){throw new slothlet.SlothletError("SCOPE_INVALID_OWNERS",{received:describeScopeReceived(owners)},null,{validationError:true})}for(const[key,owner]of Object.entries(owners)){if(typeof owner!=="string"||owner.length===0){throw new slothlet.SlothletError("INVALID_ARGUMENT",{argument:`owners.${key}`,expected:"non-empty string",received:typeof owner==="string"?"empty string":typeof owner,validationError:true})}}}const buildContextOwners=parentOwners=>{const base=parentOwners??null;let child=base;const claim=(key,owner)=>{const existing=child&&Object.prototype.hasOwnProperty.call(child,key)?child[key]:void 0;if(existing!==void 0&&existing!==owner){throw new slothlet.SlothletError("CONTEXT_KEY_OWNED",{key:String(key)},null,{validationError:true})}if(child===base)child=base?Object.assign(Object.create(null),base):Object.create(null);child[key]=owner};if(Array.isArray(protect))for(const k of protect)claim(k,PROTECT_SENTINEL);if(owners&&typeof owners==="object")for(const[k,o]of Object.entries(owners))claim(k,o);return child};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,__contextOwners:buildContextOwners(currentStore.__contextOwners)};if(currentStore[TRUSTED_ROOT]===true){Object.defineProperty(childStore,TRUSTED_ROOT,{value:true,configurable:true})}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,__contextOwners:buildContextOwners(currentStore.__contextOwners)};if(currentStore[TRUSTED_ROOT]===true){Object.defineProperty(childStore,TRUSTED_ROOT,{value:true,configurable:true})}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.config.collectLifecycleHooks){const nestedHooks=(await slothlet._collectLifecycleHooks("destroy")).reverse();for(const{fn,receiver}of nestedHooks){try{await Reflect.apply(fn,receiver,[])}catch{}}}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};