## @cldmv/slothlet >

Slothlet is a module-loading framework for Node.js (ESM-first) that scans a directory of source files > and assembles them into a single, cohesive API object with zero runtime dependencies.

>

Key Features:

>

> **Structure** [@cldmv/slothlet(config)](#at_cldmv_slash_slothlet) ⇒ Promise.<SlothletAPI> * [.destroy()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_destroy) * [.shutdown()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_shutdown) * .slothlet ⇒ object * .env ⇒ Readonly.<Record.<string, (string|undefined)>> * .api ⇒ object * [.add()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-api-add) * [.reload()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-api-reload) * [.remove()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-api-remove) * .modules ⇒ object * [.discover()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-api-modules-discover) * [.sort()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-api-modules-sort) * [.addModule()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-api-modules-addModule) * [.addModules()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-api-modules-addModules) * [.removeModule()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-api-modules-removeModule) * [.addDiscovered()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-api-modules-addDiscovered) * [.getDiscoveryCache()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-api-modules-getDiscoveryCache) * [.clearDiscoveryCache()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-api-modules-clearDiscoveryCache) * [.getStaleMounts()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-api-modules-getStaleMounts) * .context ⇒ object * [.get()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-context-get) * [.inspect()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-context-inspect) * [.run()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-context-run) * [.scope()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-context-scope) * [.set()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-context-set) * \[.diag\] ⇒ object * \[.caches\] ⇒ object * [\[.get\]()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-diag-caches-get) * [\[.getAllModuleIDs\]()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-diag-caches-getAllModuleIDs) * [\[.has\]()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-diag-caches-has) * \[.context\] ⇒ object * [\[.describe\]()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-diag-describe) * [\[.getAPI\]()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-diag-getAPI) * [\[.getOwnership\]()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-diag-getOwnership) * \[.hook\] ⇒ object * [\[.inspect\]()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-diag-inspect) * \[.owner\] ⇒ object * [\[.get\]()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-diag-owner-get) * \[.reference\] ⇒ object * [\[.SlothletWarning\]()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-diag-SlothletWarning) * .hook ⇒ object * [.clear()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-hook-clear) * [.disable()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-hook-disable) * [.disablePattern()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-hook-disablePattern) * [.enable()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-hook-enable) * [.enablePattern()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-hook-enablePattern) * [.list()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-hook-list) * [.off()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-hook-off) * [.on()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-hook-on) * .pin ⇒ object * .enabled ⇒ boolean * [.enable()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-hook-pin-enable) * [.disable()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-hook-pin-disable) * [.remove()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-hook-remove) * [.resetPatternFilter()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-hook-resetPatternFilter) * .lifecycle ⇒ object * [.off()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-lifecycle-off) * [.on()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-lifecycle-on) * .materialize ⇒ object * [.get()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-materialize-get) * .materialized ⇒ boolean * [.wait()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-materialize-wait) * .metadata ⇒ object * [.caller()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-metadata-caller) * [.get()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-metadata-get) * [.remove()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-metadata-remove) * [.getFor()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-metadata-getFor) * [.removeFor()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-metadata-removeFor) * [.self()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-metadata-self) * [.set()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-metadata-set) * [.setFor()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-metadata-setFor) * [.setGlobal()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-metadata-setGlobal) * .owner ⇒ object * [.get()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-owner-get) * .ownership ⇒ object * [.get()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-ownership-get) * [.unregister()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-ownership-unregister) * .permissions ⇒ object * .control ⇒ object * .enabled ⇒ boolean * [.enable()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-permissions-control-enable) * [.disable()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-permissions-control-disable) * .readGatingEnabled ⇒ boolean * [.readGating()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-permissions-control-readGating) * .versioning ⇒ object * [.list()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-versioning-list) * [.setDefault()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-versioning-setDefault) * [.unregister()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-versioning-unregister) * [.getVersionMetadata()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-versioning-getVersionMetadata) * [.setVersionMetadata()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-versioning-setVersionMetadata) * [.lockCaller()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-lockCaller) * [.bind()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-bind) * \[.reference\] ⇒ object * [.reload()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-reload) * [.run()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-run) * [.scope()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-scope) * [.shutdown()](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI_prop_slothlet-shutdown) [@cldmv/slothlet/runtime](#at_cldmv_slash_slothlet_slash_runtime) **Example** ```js // ESM default import (recommended) import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: "./api" }); await api.math.add(2, 3); // 5 await api.slothlet.shutdown(); ``` **Example** ```js // ESM named import import { slothlet } from "@cldmv/slothlet"; ``` **Example** ```js // CommonJS require const slothlet = require("@cldmv/slothlet"); ``` **Example** ```js // Lazy loading mode — modules loaded on first access const api = await slothlet({ base: "./api", mode: "lazy" }); ``` **Example** ```js // With per-request context isolation const api = await slothlet({ base: "./api", context: { db, logger }, runtime: "async" }); // Inside an API module, access context via: // import { context } from "@cldmv/slothlet/runtime"; ``` **Example** ```js // With hook interception const api = await slothlet({ base: "./api", hook: true }); api.slothlet.hook.on("before", "math.*", (endpoint, args) => { console.log("calling:", endpoint, args); }); ``` **Example** ```js // Multiple independent instances const api1 = await slothlet({ base: "./api" }); const api2 = await slothlet({ base: "./other-api" }); ``` **Example** ```js // Shutdown when done await api.slothlet.shutdown(); ``` * * * ### @cldmv/slothlet(config) ⇒ Promise.<SlothletAPI> >

Create a new Slothlet instance and load an API from a directory. > This is the sole public entry point for slothlet. Each call produces an independent > API instance with its own component graph, context store, and lifecycle.

> | Param | Type | Default | Description | | --- | --- | --- | --- | | config | [SlothletOptions](#typedef_module_at_cldmv_slash_slothlet_SlothletOptions) | |

Configuration options

| **Returns**: - Promise.<SlothletAPI>

Fully loaded, proxy-based API object

**Example** ```js // ESM default import (recommended) import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: "./api" }); await api.math.add(2, 3); // 5 await api.slothlet.shutdown(); ``` **Example** ```js // ESM named import import { slothlet } from "@cldmv/slothlet"; ``` **Example** ```js // CommonJS require const slothlet = require("@cldmv/slothlet"); ``` **Example** ```js // Lazy loading mode — modules loaded on first access const api = await slothlet({ base: "./api", mode: "lazy" }); ``` **Example** ```js // With per-request context isolation const api = await slothlet({ base: "./api", context: { db, logger }, runtime: "async" }); // Inside an API module, access context via: // import { context } from "@cldmv/slothlet/runtime"; ``` **Example** ```js // With hook interception const api = await slothlet({ base: "./api", hook: true }); api.slothlet.hook.on("before", "math.*", (endpoint, args) => { console.log("calling:", endpoint, args); }); ``` **Example** ```js // Multiple independent instances const api1 = await slothlet({ base: "./api" }); const api2 = await slothlet({ base: "./other-api" }); ``` **Example** ```js // Shutdown when done await api.slothlet.shutdown(); ``` * * * ### SlothletOptions : object

Configuration options passed to slothlet().

**Kind**: typedef **Scope**: inner #### api.resolveModuleSpecifier() Browser-mode module resolver: (fileEntry: {path, name, fullName}) => string | URL. Maps a manifest file entry to an importable URL or bare specifier. Defaults to resolving against base as a file:// URL. Override to point at a CDN, bundler virtual module, or other browser-friendly source. **Kind**: function property of [SlothletOptions](#typedef_module_at_cldmv_slash_slothlet_SlothletOptions) * * * #### api.versionDispatcher() Version routing discriminator for versioned API paths.

**Kind**: function property of [SlothletOptions](#typedef_module_at_cldmv_slash_slothlet_SlothletOptions) * * * | Property | Type | Default | Description | | --- | --- | --- | --- | | [base] | string | | Directory (node mode) or file:// URL / base URL (browser mode) to load API modules from. Required in both modes. Plain filesystem paths are automatically converted to `file://` URLs by the default browser-mode resolver. | | [dir] | string | | Deprecated alias for `base`. Still accepted; emits a `V3_CONFIG_DEPRECATED` warning unless `silent: true`. Will be removed in v4. | | [mode] | "eager" \| "lazy" | "eager" | Loading strategy. | | [runtime] | "async" \| "live" | "async" | Context propagation runtime. | | [apiDepth] | number | Infinity | Directory traversal depth. `Infinity` scans all subdirectories (default). `0` scans only the root. | | [hidden] | string \| Array. | | Glob or array of globs hiding files and folders from the API, matched against each entry's path relative to `base` (folder-style `a/b` or dotted `a.b`; `*` one segment, `**` any depth, `?` one char, `{a,b}` alternation, `!` negation). Files match on their extension-stripped path. Applies on top of the built-in rule that `.`/`__`-prefixed names are always hidden. Also accepted per-call by `api.slothlet.api.add(path, dir, { hidden })`, where globs are relative to the added folder. | | [scanHiddenFolders] | boolean | false | Deprecated escape hatch: restore the pre-v3.11 behavior of scanning `.`/`__`-prefixed folders. Emits a `CONFIG_SCAN_HIDDEN_FOLDERS_DEPRECATED` warning when supplied (unless `silent: true`). Will be removed in v4. | | [context] | object \| null | null | Object merged into the per-request context accessible inside API functions via `import { context } from "@cldmv/slothlet/runtime"`. | | [reference] | object \| null | null | Object whose properties are merged directly onto the root API and also available as `api.slothlet.reference`. | | [scope] | Object | | Controls how per-request scope data is merged. `"shallow"` merges top-level keys; `"deep"` recurses into nested objects. | | [api] | object | | API build and mutation settings. | | [api.collision] | string \| Object | "merge" | Collision strategy when two modules export the same path. Modes: `"merge"` (default), `"merge-replace"`, `"replace"`, `"skip"`, `"warn"`, `"error"`. Pass an object to use different strategies for the initial build vs. runtime `api.slothlet.api.add()` calls. | | [api.mutations] | object | {add:true,remove:true,reload:true} | Enable or disable runtime mutation methods on `api.slothlet.api`. Object with boolean keys `add`, `remove`, `reload` (all default `true`). | | [hook] | boolean \| string \| object | false | Hook system configuration. | | [debug] | boolean \| object | false | Enable verbose internal logging. `true` enables all categories. Pass an object with sub-keys `builder`, `api`, `index`, `modes`, `wrapper`, `ownership`, `context` to target specific subsystems. | | [silent] | boolean | false | Suppress all console output from slothlet (warnings, deprecations). Does not affect `debug`. | | [diagnostics] | boolean | false | Enable the `api.slothlet.diag.*` introspection namespace. Intended for testing; do not enable in production. | | [tracking] | boolean \| object | false | Enable internal tracking. Pass `true` or `{ materialization: true }` to track lazy-mode materialization progress. | | [backgroundMaterialize] | boolean | false | When `mode: "lazy"`, immediately begins materializing all paths in the background after init. | | [i18n] | object | | Internationalization settings (dev-facing, process-global). `{ language: string }` — selects the locale for framework messages (e.g. `"en-us"`, `"fr-fr"`, `"ja-jp"`). | | [platform] | "browser" \| "node" | | Execution-environment target. Controls whether filesystem-dependent code paths run. Independent of `env` (the `process.env` snapshot). | | [env] | object \| null | | `process.env` snapshot configuration (Node mode). Independent of `platform`. | | [env.include] | Array. | | Allowlist of environment variable names to capture. Only string entries are used. | | [manifest] | Object | | Pre-generated directory structure for browser mode. Produced at build time by `generateManifest()` from `@cldmv/slothlet/helpers/generate-manifest`. Required when `platform: "browser"`. Presence of `manifest` auto-triggers browser mode without needing an explicit `platform: "browser"`. | | [suppressFixes] | Array. | | Opt out of specific bug-fix behaviors that landed in v3 and become permanent in v4. Each entry uses the `_` form (e.g. `"C03_116"`). Each listed rule emits a `WARN_SUPPRESS_FIX_ACTIVE` deprecation warning unless `silent: true`. Temporary escape hatch — will be removed in v4 when the corrected behaviors become permanent. | | [typescript] | boolean \| "fast" \| "strict" \| object | false | TypeScript support. | * * * ### SlothletAPI : object

Bound API object returned by slothlet(). The root contains all loaded module exports plus the reserved slothlet namespace.

**Kind**: typedef **Scope**: inner #### api.destroy() ⇒ void Like shutdown() but additionally invokes registered destroy hooks before teardown. **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) **Returns**: void **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api' }); await api.destroy(); ``` **Example** ```javascript // ESM usage via slothlet API (inside async function) async function example() { const { default: slothlet } = await import("@cldmv/slothlet"); const api = await slothlet({ base: './api' }); await api.destroy(); } ``` **Example** ```javascript // CJS usage via slothlet API (top-level) let slothlet; (async () => { ({ slothlet } = await import("@cldmv/slothlet")); const api = await slothlet({ base: './api' }); await api.destroy(); })(); ``` **Example** ```javascript // CJS usage via slothlet API (inside async function) const slothlet = require("@cldmv/slothlet"); const api = await slothlet({ base: './api' }); await api.destroy(); ``` * * * #### api.shutdown() ⇒ void Convenience alias for slothlet.shutdown(). Shuts down the instance and invokes any user-provided shutdown hook first. **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) **Returns**: void **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api' }); await api.shutdown(); ``` **Example** ```javascript // ESM usage via slothlet API (inside async function) async function example() { const { default: slothlet } = await import("@cldmv/slothlet"); const api = await slothlet({ base: './api' }); await api.shutdown(); } ``` **Example** ```javascript // CJS usage via slothlet API (top-level) let slothlet; (async () => { ({ slothlet } = await import("@cldmv/slothlet")); const api = await slothlet({ base: './api' }); await api.shutdown(); })(); ``` **Example** ```javascript // CJS usage via slothlet API (inside async function) const slothlet = require("@cldmv/slothlet"); const api = await slothlet({ base: './api' }); await api.shutdown(); ``` * * * #### api.slothlet.api.add(apiPath, folderPath, [options]) ⇒ Promise.<void> Mount a new API module at runtime. **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) | Param | Type | Description | | --- | --- | --- | | apiPath | string | | | folderPath | string | | | [options] | Object | | **Returns**: Promise.<void> **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api' }); await api.slothlet.api.add('utils.math', './api/utils/math'); ``` **Example** ```javascript // ESM usage via slothlet API (inside async function) async function example() { const { default: slothlet } = await import("@cldmv/slothlet"); const api = await slothlet({ base: './api' }); await api.slothlet.api.add('utils.math', './api/utils/math'); } ``` **Example** ```javascript // CJS usage via slothlet API (top-level) let slothlet; (async () => { ({ slothlet } = await import("@cldmv/slothlet")); const api = await slothlet({ base: './api' }); await api.slothlet.api.add('utils.math', './api/utils/math'); })(); ``` **Example** ```javascript // CJS usage via slothlet API (inside async function) const slothlet = require("@cldmv/slothlet"); const api = await slothlet({ base: './api' }); await api.slothlet.api.add('utils.math', './api/utils/math'); ``` * * * #### api.slothlet.api.reload([pathOrModuleId], [options]) ⇒ Promise.<void> Hot-reload a specific module or directory path. **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) | Param | Type | Description | | --- | --- | --- | | [pathOrModuleId] | string\|null | | | [options] | Object | | **Returns**: Promise.<void> **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api' }); // Reload a specific module await api.slothlet.api.reload('utils.math'); // Reload everything await api.slothlet.api.reload(); ``` **Example** ```javascript // ESM usage via slothlet API (inside async function) async function example() { const { default: slothlet } = await import("@cldmv/slothlet"); const api = await slothlet({ base: './api' }); // Reload a specific module await api.slothlet.api.reload('utils.math'); // Reload everything await api.slothlet.api.reload(); } ``` **Example** ```javascript // CJS usage via slothlet API (top-level) let slothlet; (async () => { ({ slothlet } = await import("@cldmv/slothlet")); const api = await slothlet({ base: './api' }); // Reload a specific module await api.slothlet.api.reload('utils.math'); // Reload everything await api.slothlet.api.reload(); })(); ``` **Example** ```javascript // CJS usage via slothlet API (inside async function) const slothlet = require("@cldmv/slothlet"); const api = await slothlet({ base: './api' }); // Reload a specific module await api.slothlet.api.reload('utils.math'); // Reload everything await api.slothlet.api.reload(); ``` * * * #### api.slothlet.api.remove(pathOrModuleId) ⇒ Promise.<void> Unmount an API module at runtime. **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) | Param | Type | Description | | --- | --- | --- | | pathOrModuleId | string | | **Returns**: Promise.<void> **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api' }); await api.slothlet.api.remove('utils.math'); ``` **Example** ```javascript // ESM usage via slothlet API (inside async function) async function example() { const { default: slothlet } = await import("@cldmv/slothlet"); const api = await slothlet({ base: './api' }); await api.slothlet.api.remove('utils.math'); } ``` **Example** ```javascript // CJS usage via slothlet API (top-level) let slothlet; (async () => { ({ slothlet } = await import("@cldmv/slothlet")); const api = await slothlet({ base: './api' }); await api.slothlet.api.remove('utils.math'); })(); ``` **Example** ```javascript // CJS usage via slothlet API (inside async function) const slothlet = require("@cldmv/slothlet"); const api = await slothlet({ base: './api' }); await api.slothlet.api.remove('utils.math'); ``` * * * #### api.slothlet.api.modules.discover([options]) ⇒ Promise.<DiscoverResult[]> Walk the filesystem for slothlet modules; replace the per-instance discovery cache and return the fresh results. **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) | Param | Type | Description | | --- | --- | --- | | [options] | Object | | **Returns**: Promise.<DiscoverResult[]> **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api' }); const found = await api.slothlet.api.modules.discover({ scanRoot: process.cwd(), prefix: "@cldmv/packrat-driver-" }); ``` * * * #### api.slothlet.api.modules.sort(results, [comparator]) ⇒ DiscoverResult[] Pure sort; default comparator is priority desc with packageName asc tiebreak. Pass a custom comparator to override. **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) | Param | Type | Description | | --- | --- | --- | | results | DiscoverResult[] | | | [comparator] | function | | **Returns**: DiscoverResult[] **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api' }); const ordered = api.slothlet.api.modules.sort(await api.slothlet.api.modules.discover()); ``` * * * #### api.slothlet.api.modules.addModule(nameOrResult, [options]) ⇒ Promise.<MountResult> Mount one module by package name (cache lookup) or by DiscoverResult directly. Lazy-triggers discover() when the cache is empty. **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) | Param | Type | Description | | --- | --- | --- | | nameOrResult | string\|DiscoverResult | | | [options] | Object | | **Returns**: Promise.<MountResult> **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api' }); await api.slothlet.api.modules.addModule("@cldmv/packrat-driver-opensearch"); ``` * * * #### api.slothlet.api.modules.addModules(items, [options]) ⇒ Promise.<MountResult[]|Object> Batch mount a list of modules. Accepts a heterogeneous Array<string | DiscoverResult>. Supports onFailure: "throw" | "rollback" | "best-effort" and concurrency for parallel batches; under best-effort returns the { mounted, failed } aggregate instead of a plain array. **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) | Param | Type | Description | | --- | --- | --- | | items | Array.<string\|DiscoverResult> | | | [options] | Object | | **Returns**: Promise.<MountResult[]|Object> **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api' }); await api.slothlet.api.modules.addModules(["@org/a", "@org/b"], { onFailure: "best-effort", concurrency: 4 }); ``` * * * #### api.slothlet.api.modules.removeModule(name, [options]) ⇒ Promise.<void> Unmount a previously-mounted module. **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) | Param | Type | Description | | --- | --- | --- | | name | string | | | [options] | Object | | **Returns**: Promise.<void> **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api' }); await api.slothlet.api.modules.removeModule("@cldmv/packrat-driver-opensearch"); ``` * * * #### api.slothlet.api.modules.addDiscovered([options]) ⇒ Promise.<MountResult[]> One-shot convenience: chains discover()sort()addModules() for the most common boot-time flow. **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) | Param | Type | Description | | --- | --- | --- | | [options] | Object | | **Returns**: Promise.<MountResult[]> **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api' }); await api.slothlet.api.modules.addDiscovered({ scanRoot: process.cwd(), prefix: "@cldmv/packrat-driver-" }); ``` * * * #### api.slothlet.api.modules.getDiscoveryCache() ⇒ DiscoverResult[] Snapshot of the current discovery cache. Returns the same DiscoverResult[] shape discover() produces. **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) **Returns**: DiscoverResult[] **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api' }); const cached = api.slothlet.api.modules.getDiscoveryCache(); ``` * * * #### api.slothlet.api.modules.clearDiscoveryCache() ⇒ void Empty the discovery cache (does NOT unmount anything already mounted). **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) **Returns**: void **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api' }); api.slothlet.api.modules.clearDiscoveryCache(); ``` * * * #### api.slothlet.api.modules.getStaleMounts() ⇒ MountResult[] Reconciliation aid: returns mounts whose ${packageName}@${version} no longer appears in the discovery cache. Useful for hot-reload prune logic. **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) **Returns**: MountResult[] **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api' }); const stale = api.slothlet.api.modules.getStaleMounts(); ``` * * * #### api.slothlet.context.get([key]) ⇒ * Get a value from the current per-request context store. **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) | Param | Type | Description | | --- | --- | --- | | [key] | string | | **Returns**: * **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api' }); await api.slothlet.context.run({ userId: 42 }, async () => { const userId = api.slothlet.context.get('userId'); // 42 }); ``` **Example** ```javascript // ESM usage via slothlet API (inside async function) async function example() { const { default: slothlet } = await import("@cldmv/slothlet"); const api = await slothlet({ base: './api' }); await api.slothlet.context.run({ userId: 42 }, async () => { const userId = api.slothlet.context.get('userId'); // 42 }); } ``` **Example** ```javascript // CJS usage via slothlet API (top-level) let slothlet; (async () => { ({ slothlet } = await import("@cldmv/slothlet")); const api = await slothlet({ base: './api' }); await api.slothlet.context.run({ userId: 42 }, async () => { const userId = api.slothlet.context.get('userId'); // 42 }); })(); ``` **Example** ```javascript // CJS usage via slothlet API (inside async function) const slothlet = require("@cldmv/slothlet"); const api = await slothlet({ base: './api' }); await api.slothlet.context.run({ userId: 42 }, async () => { const userId = api.slothlet.context.get('userId'); // 42 }); ``` * * * #### api.slothlet.context.inspect() ⇒ Object Return a snapshot of the current context state (for debugging). **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) **Returns**: Object **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api' }); await api.slothlet.context.run({ userId: 42 }, async () => { const snapshot = api.slothlet.context.inspect(); // { data: { userId: 42 }, ... } }); ``` **Example** ```javascript // ESM usage via slothlet API (inside async function) async function example() { const { default: slothlet } = await import("@cldmv/slothlet"); const api = await slothlet({ base: './api' }); await api.slothlet.context.run({ userId: 42 }, async () => { const snapshot = api.slothlet.context.inspect(); // { data: { userId: 42 }, ... } }); } ``` **Example** ```javascript // CJS usage via slothlet API (top-level) let slothlet; (async () => { ({ slothlet } = await import("@cldmv/slothlet")); const api = await slothlet({ base: './api' }); await api.slothlet.context.run({ userId: 42 }, async () => { const snapshot = api.slothlet.context.inspect(); // { data: { userId: 42 }, ... } }); })(); ``` **Example** ```javascript // CJS usage via slothlet API (inside async function) const slothlet = require("@cldmv/slothlet"); const api = await slothlet({ base: './api' }); await api.slothlet.context.run({ userId: 42 }, async () => { const snapshot = api.slothlet.context.inspect(); // { data: { userId: 42 }, ... } }); ``` * * * #### api.slothlet.context.run(contextData, callback, args) ⇒ * Execute a callback with isolated context data merged in. **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) | Param | Type | Description | | --- | --- | --- | | contextData | Object | | | callback | function | | | args | * | | **Returns**: * **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api' }); const result = await api.slothlet.context.run({ userId: 42 }, async () => { return api.myModule.getUser(); // sees context.userId = 42 }); ``` **Example** ```javascript // ESM usage via slothlet API (inside async function) async function example() { const { default: slothlet } = await import("@cldmv/slothlet"); const api = await slothlet({ base: './api' }); const result = await api.slothlet.context.run({ userId: 42 }, async () => { return api.myModule.getUser(); // sees context.userId = 42 }); } ``` **Example** ```javascript // CJS usage via slothlet API (top-level) let slothlet; (async () => { ({ slothlet } = await import("@cldmv/slothlet")); const api = await slothlet({ base: './api' }); const result = await api.slothlet.context.run({ userId: 42 }, async () => { return api.myModule.getUser(); // sees context.userId = 42 }); })(); ``` **Example** ```javascript // CJS usage via slothlet API (inside async function) const slothlet = require("@cldmv/slothlet"); const api = await slothlet({ base: './api' }); const result = await api.slothlet.context.run({ userId: 42 }, async () => { return api.myModule.getUser(); // sees context.userId = 42 }); ``` * * * #### api.slothlet.context.scope(options) ⇒ * Execute a function with structured context options (context, fn, args, merge, isolation). **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) | Param | Type | Description | | --- | --- | --- | | options | Object | | **Returns**: * **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api' }); const result = await api.slothlet.context.scope({ context: { userId: 42 }, fn: async () => api.myModule.getUser() }); ``` **Example** ```javascript // ESM usage via slothlet API (inside async function) async function example() { const { default: slothlet } = await import("@cldmv/slothlet"); const api = await slothlet({ base: './api' }); const result = await api.slothlet.context.scope({ context: { userId: 42 }, fn: async () => api.myModule.getUser() }); } ``` **Example** ```javascript // CJS usage via slothlet API (top-level) let slothlet; (async () => { ({ slothlet } = await import("@cldmv/slothlet")); const api = await slothlet({ base: './api' }); const result = await api.slothlet.context.scope({ context: { userId: 42 }, fn: async () => api.myModule.getUser() }); })(); ``` **Example** ```javascript // CJS usage via slothlet API (inside async function) const slothlet = require("@cldmv/slothlet"); const api = await slothlet({ base: './api' }); const result = await api.slothlet.context.scope({ context: { userId: 42 }, fn: async () => api.myModule.getUser() }); ``` * * * #### api.slothlet.context.set(key, value) ⇒ void Set a value in the current per-request context store. **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) | Param | Type | Description | | --- | --- | --- | | key | string | | | value | * | | **Returns**: void **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api' }); await api.slothlet.context.run({}, async () => { api.slothlet.context.set('traceId', 'abc-123'); }); ``` **Example** ```javascript // ESM usage via slothlet API (inside async function) async function example() { const { default: slothlet } = await import("@cldmv/slothlet"); const api = await slothlet({ base: './api' }); await api.slothlet.context.run({}, async () => { api.slothlet.context.set('traceId', 'abc-123'); }); } ``` **Example** ```javascript // CJS usage via slothlet API (top-level) let slothlet; (async () => { ({ slothlet } = await import("@cldmv/slothlet")); const api = await slothlet({ base: './api' }); await api.slothlet.context.run({}, async () => { api.slothlet.context.set('traceId', 'abc-123'); }); })(); ``` **Example** ```javascript // CJS usage via slothlet API (inside async function) const slothlet = require("@cldmv/slothlet"); const api = await slothlet({ base: './api' }); await api.slothlet.context.run({}, async () => { api.slothlet.context.set('traceId', 'abc-123'); }); ``` * * * #### api.slothlet.diag.caches.get() ⇒ Object Get full cache diagnostic data ({ totalCaches, caches[] }). Only available when diagnostics: true. > **Requires**: `diagnostics: true` in config **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) **Returns**: Object **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api', diagnostics: true }); const cacheData = api.slothlet.diag.caches.get(); // { totalCaches: 2, caches: [...] } ``` **Example** ```javascript // ESM usage via slothlet API (inside async function) async function example() { const { default: slothlet } = await import("@cldmv/slothlet"); const api = await slothlet({ base: './api', diagnostics: true }); const cacheData = api.slothlet.diag.caches.get(); // { totalCaches: 2, caches: [...] } } ``` **Example** ```javascript // CJS usage via slothlet API (top-level) let slothlet; (async () => { ({ slothlet } = await import("@cldmv/slothlet")); const api = await slothlet({ base: './api', diagnostics: true }); const cacheData = api.slothlet.diag.caches.get(); // { totalCaches: 2, caches: [...] } })(); ``` **Example** ```javascript // CJS usage via slothlet API (inside async function) const slothlet = require("@cldmv/slothlet"); const api = await slothlet({ base: './api', diagnostics: true }); const cacheData = api.slothlet.diag.caches.get(); // { totalCaches: 2, caches: [...] } ``` * * * #### api.slothlet.diag.caches.getAllModuleIDs() ⇒ string[] Return all moduleIDs currently in cache. Only available when diagnostics: true. > **Requires**: `diagnostics: true` in config **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) **Returns**: string[] **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api', diagnostics: true }); const ids = api.slothlet.diag.caches.getAllModuleIDs(); // ['utils/math.mjs', 'utils/strings.mjs'] ``` **Example** ```javascript // ESM usage via slothlet API (inside async function) async function example() { const { default: slothlet } = await import("@cldmv/slothlet"); const api = await slothlet({ base: './api', diagnostics: true }); const ids = api.slothlet.diag.caches.getAllModuleIDs(); // ['utils/math.mjs', 'utils/strings.mjs'] } ``` **Example** ```javascript // CJS usage via slothlet API (top-level) let slothlet; (async () => { ({ slothlet } = await import("@cldmv/slothlet")); const api = await slothlet({ base: './api', diagnostics: true }); const ids = api.slothlet.diag.caches.getAllModuleIDs(); // ['utils/math.mjs', 'utils/strings.mjs'] })(); ``` **Example** ```javascript // CJS usage via slothlet API (inside async function) const slothlet = require("@cldmv/slothlet"); const api = await slothlet({ base: './api', diagnostics: true }); const ids = api.slothlet.diag.caches.getAllModuleIDs(); // ['utils/math.mjs', 'utils/strings.mjs'] ``` * * * #### api.slothlet.diag.caches.has(moduleID) ⇒ boolean Check whether a cache entry exists for a given moduleID. Only available when diagnostics: true. > **Requires**: `diagnostics: true` in config **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) | Param | Type | Description | | --- | --- | --- | | moduleID | string | | **Returns**: boolean **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api', diagnostics: true }); const exists = api.slothlet.diag.caches.has('utils/math.mjs'); // true or false ``` **Example** ```javascript // ESM usage via slothlet API (inside async function) async function example() { const { default: slothlet } = await import("@cldmv/slothlet"); const api = await slothlet({ base: './api', diagnostics: true }); const exists = api.slothlet.diag.caches.has('utils/math.mjs'); // true or false } ``` **Example** ```javascript // CJS usage via slothlet API (top-level) let slothlet; (async () => { ({ slothlet } = await import("@cldmv/slothlet")); const api = await slothlet({ base: './api', diagnostics: true }); const exists = api.slothlet.diag.caches.has('utils/math.mjs'); // true or false })(); ``` **Example** ```javascript // CJS usage via slothlet API (inside async function) const slothlet = require("@cldmv/slothlet"); const api = await slothlet({ base: './api', diagnostics: true }); const exists = api.slothlet.diag.caches.has('utils/math.mjs'); // true or false ``` * * * #### api.slothlet.diag.describe([showAll]) ⇒ * Describe API structure. Pass true to return the full API object; omit for top-level keys only. Only available when diagnostics: true. > **Requires**: `diagnostics: true` in config **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) | Param | Type | Description | | --- | --- | --- | | [showAll] | boolean | | **Returns**: * **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api', diagnostics: true }); const keys = api.slothlet.diag.describe(); const full = api.slothlet.diag.describe(true); ``` **Example** ```javascript // ESM usage via slothlet API (inside async function) async function example() { const { default: slothlet } = await import("@cldmv/slothlet"); const api = await slothlet({ base: './api', diagnostics: true }); const keys = api.slothlet.diag.describe(); const full = api.slothlet.diag.describe(true); } ``` **Example** ```javascript // CJS usage via slothlet API (top-level) let slothlet; (async () => { ({ slothlet } = await import("@cldmv/slothlet")); const api = await slothlet({ base: './api', diagnostics: true }); const keys = api.slothlet.diag.describe(); const full = api.slothlet.diag.describe(true); })(); ``` **Example** ```javascript // CJS usage via slothlet API (inside async function) const slothlet = require("@cldmv/slothlet"); const api = await slothlet({ base: './api', diagnostics: true }); const keys = api.slothlet.diag.describe(); const full = api.slothlet.diag.describe(true); ``` * * * #### api.slothlet.diag.getAPI() ⇒ Object Return the live bound API proxy object. Only available when diagnostics: true. > **Requires**: `diagnostics: true` in config **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) **Returns**: Object **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api', diagnostics: true }); const proxy = api.slothlet.diag.getAPI(); // the live bound API proxy ``` **Example** ```javascript // ESM usage via slothlet API (inside async function) async function example() { const { default: slothlet } = await import("@cldmv/slothlet"); const api = await slothlet({ base: './api', diagnostics: true }); const proxy = api.slothlet.diag.getAPI(); // the live bound API proxy } ``` **Example** ```javascript // CJS usage via slothlet API (top-level) let slothlet; (async () => { ({ slothlet } = await import("@cldmv/slothlet")); const api = await slothlet({ base: './api', diagnostics: true }); const proxy = api.slothlet.diag.getAPI(); // the live bound API proxy })(); ``` **Example** ```javascript // CJS usage via slothlet API (inside async function) const slothlet = require("@cldmv/slothlet"); const api = await slothlet({ base: './api', diagnostics: true }); const proxy = api.slothlet.diag.getAPI(); // the live bound API proxy ``` * * * #### api.slothlet.diag.getOwnership() ⇒ Object Return ownership diagnostics for all registered API paths. Only available when diagnostics: true. > **Requires**: `diagnostics: true` in config **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) **Returns**: Object **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api', diagnostics: true }); const ownership = api.slothlet.diag.getOwnership(); ``` **Example** ```javascript // ESM usage via slothlet API (inside async function) async function example() { const { default: slothlet } = await import("@cldmv/slothlet"); const api = await slothlet({ base: './api', diagnostics: true }); const ownership = api.slothlet.diag.getOwnership(); } ``` **Example** ```javascript // CJS usage via slothlet API (top-level) let slothlet; (async () => { ({ slothlet } = await import("@cldmv/slothlet")); const api = await slothlet({ base: './api', diagnostics: true }); const ownership = api.slothlet.diag.getOwnership(); })(); ``` **Example** ```javascript // CJS usage via slothlet API (inside async function) const slothlet = require("@cldmv/slothlet"); const api = await slothlet({ base: './api', diagnostics: true }); const ownership = api.slothlet.diag.getOwnership(); ``` * * * #### api.slothlet.diag.inspect() ⇒ Object Return a full diagnostic snapshot of current instance state. Only available when diagnostics: true. > **Requires**: `diagnostics: true` in config **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) **Returns**: Object **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api', diagnostics: true }); const snapshot = api.slothlet.diag.inspect(); console.log(snapshot.modules, snapshot.hooks); ``` **Example** ```javascript // ESM usage via slothlet API (inside async function) async function example() { const { default: slothlet } = await import("@cldmv/slothlet"); const api = await slothlet({ base: './api', diagnostics: true }); const snapshot = api.slothlet.diag.inspect(); console.log(snapshot.modules, snapshot.hooks); } ``` **Example** ```javascript // CJS usage via slothlet API (top-level) let slothlet; (async () => { ({ slothlet } = await import("@cldmv/slothlet")); const api = await slothlet({ base: './api', diagnostics: true }); const snapshot = api.slothlet.diag.inspect(); console.log(snapshot.modules, snapshot.hooks); })(); ``` **Example** ```javascript // CJS usage via slothlet API (inside async function) const slothlet = require("@cldmv/slothlet"); const api = await slothlet({ base: './api', diagnostics: true }); const snapshot = api.slothlet.diag.inspect(); console.log(snapshot.modules, snapshot.hooks); ``` * * * #### api.slothlet.diag.owner.get(apiPath) ⇒ string[] Get the owning moduleIDs for a specific API path. Only available when diagnostics: true. > **Requires**: `diagnostics: true` in config **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) | Param | Type | Description | | --- | --- | --- | | apiPath | string | | **Returns**: string[] **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api', diagnostics: true }); const owners = api.slothlet.diag.owner.get('math.add'); // ['utils/math.mjs'] ``` **Example** ```javascript // ESM usage via slothlet API (inside async function) async function example() { const { default: slothlet } = await import("@cldmv/slothlet"); const api = await slothlet({ base: './api', diagnostics: true }); const owners = api.slothlet.diag.owner.get('math.add'); // ['utils/math.mjs'] } ``` **Example** ```javascript // CJS usage via slothlet API (top-level) let slothlet; (async () => { ({ slothlet } = await import("@cldmv/slothlet")); const api = await slothlet({ base: './api', diagnostics: true }); const owners = api.slothlet.diag.owner.get('math.add'); // ['utils/math.mjs'] })(); ``` **Example** ```javascript // CJS usage via slothlet API (inside async function) const slothlet = require("@cldmv/slothlet"); const api = await slothlet({ base: './api', diagnostics: true }); const owners = api.slothlet.diag.owner.get('math.add'); // ['utils/math.mjs'] ``` * * * #### api.slothlet.diag.SlothletWarning() ⇒ SlothletWarning The SlothletWarning class — access .captured for warnings emitted during tests. Only available when diagnostics: true. > **Requires**: `diagnostics: true` in config **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) **Returns**: SlothletWarning **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api', diagnostics: true }); const SlothletWarning = api.slothlet.diag.SlothletWarning; console.log(SlothletWarning.captured); // array of captured warnings ``` **Example** ```javascript // ESM usage via slothlet API (inside async function) async function example() { const { default: slothlet } = await import("@cldmv/slothlet"); const api = await slothlet({ base: './api', diagnostics: true }); const SlothletWarning = api.slothlet.diag.SlothletWarning; console.log(SlothletWarning.captured); // array of captured warnings } ``` **Example** ```javascript // CJS usage via slothlet API (top-level) let slothlet; (async () => { ({ slothlet } = await import("@cldmv/slothlet")); const api = await slothlet({ base: './api', diagnostics: true }); const SlothletWarning = api.slothlet.diag.SlothletWarning; console.log(SlothletWarning.captured); // array of captured warnings })(); ``` **Example** ```javascript // CJS usage via slothlet API (inside async function) const slothlet = require("@cldmv/slothlet"); const api = await slothlet({ base: './api', diagnostics: true }); const SlothletWarning = api.slothlet.diag.SlothletWarning; console.log(SlothletWarning.captured); // array of captured warnings ``` * * * #### api.slothlet.hook.clear([filter]) ⇒ void Alias for remove(). **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) | Param | Type | Description | | --- | --- | --- | | [filter] | Object | | **Returns**: void **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api', hook: true }); api.slothlet.hook.clear({ type: 'before' }); ``` **Example** ```javascript // ESM usage via slothlet API (inside async function) async function example() { const { default: slothlet } = await import("@cldmv/slothlet"); const api = await slothlet({ base: './api', hook: true }); api.slothlet.hook.clear({ type: 'before' }); } ``` **Example** ```javascript // CJS usage via slothlet API (top-level) let slothlet; (async () => { ({ slothlet } = await import("@cldmv/slothlet")); const api = await slothlet({ base: './api', hook: true }); api.slothlet.hook.clear({ type: 'before' }); })(); ``` **Example** ```javascript // CJS usage via slothlet API (inside async function) const slothlet = require("@cldmv/slothlet"); const api = await slothlet({ base: './api', hook: true }); api.slothlet.hook.clear({ type: 'before' }); ``` * * * #### api.slothlet.hook.disable([filter]) ⇒ void Disable hooks matching a filter (empty = disable all). **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) | Param | Type | Description | | --- | --- | --- | | [filter] | Object | | **Returns**: void **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api', hook: true }); api.slothlet.hook.disable(); // disable all api.slothlet.hook.disable({ type: 'before' }); // disable only before hooks ``` **Example** ```javascript // ESM usage via slothlet API (inside async function) async function example() { const { default: slothlet } = await import("@cldmv/slothlet"); const api = await slothlet({ base: './api', hook: true }); api.slothlet.hook.disable(); // disable all api.slothlet.hook.disable({ type: 'before' }); // disable only before hooks } ``` **Example** ```javascript // CJS usage via slothlet API (top-level) let slothlet; (async () => { ({ slothlet } = await import("@cldmv/slothlet")); const api = await slothlet({ base: './api', hook: true }); api.slothlet.hook.disable(); // disable all api.slothlet.hook.disable({ type: 'before' }); // disable only before hooks })(); ``` **Example** ```javascript // CJS usage via slothlet API (inside async function) const slothlet = require("@cldmv/slothlet"); const api = await slothlet({ base: './api', hook: true }); api.slothlet.hook.disable(); // disable all api.slothlet.hook.disable({ type: 'before' }); // disable only before hooks ``` * * * #### api.slothlet.hook.disablePattern(pattern) ⇒ number Remove a path pattern from the runtime global path filter; when the last pattern is removed the filter deactivates and hooks apply to every path again. **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) | Param | Type | Description | | --- | --- | --- | | pattern | string | | **Returns**: number **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api', hook: true }); api.slothlet.hook.enablePattern('database.'); api.slothlet.hook.disablePattern('database.'); // stop restricting ``` **Example** ```javascript // ESM usage via slothlet API (inside async function) async function example() { const { default: slothlet } = await import("@cldmv/slothlet"); const api = await slothlet({ base: './api', hook: true }); api.slothlet.hook.disablePattern('database.'); } ``` **Example** ```javascript // CJS usage via slothlet API (top-level) let slothlet; (async () => { ({ slothlet } = await import("@cldmv/slothlet")); const api = await slothlet({ base: './api', hook: true }); api.slothlet.hook.disablePattern('database.'); })(); ``` **Example** ```javascript // CJS usage via slothlet API (inside async function) const slothlet = require("@cldmv/slothlet"); const api = await slothlet({ base: './api', hook: true }); api.slothlet.hook.disablePattern('database.*'); ``` * * * #### api.slothlet.hook.enable([filter]) ⇒ void Enable hooks matching a filter (empty = enable all). **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) | Param | Type | Description | | --- | --- | --- | | [filter] | Object | | **Returns**: void **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api', hook: true }); api.slothlet.hook.disable(); // later... api.slothlet.hook.enable(); // re-enable all ``` **Example** ```javascript // ESM usage via slothlet API (inside async function) async function example() { const { default: slothlet } = await import("@cldmv/slothlet"); const api = await slothlet({ base: './api', hook: true }); api.slothlet.hook.disable(); // later... api.slothlet.hook.enable(); // re-enable all } ``` **Example** ```javascript // CJS usage via slothlet API (top-level) let slothlet; (async () => { ({ slothlet } = await import("@cldmv/slothlet")); const api = await slothlet({ base: './api', hook: true }); api.slothlet.hook.disable(); // later... api.slothlet.hook.enable(); // re-enable all })(); ``` **Example** ```javascript // CJS usage via slothlet API (inside async function) const slothlet = require("@cldmv/slothlet"); const api = await slothlet({ base: './api', hook: true }); api.slothlet.hook.disable(); // later... api.slothlet.hook.enable(); // re-enable all ``` * * * #### api.slothlet.hook.enablePattern(pattern) ⇒ number Restrict hook execution to an API path pattern at runtime (global path filter; the runtime form of hook.pattern). Distinct from enable/disable, which toggle individual registered hooks. **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) | Param | Type | Description | | --- | --- | --- | | pattern | string | | **Returns**: number **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api', hook: true }); api.slothlet.hook.enablePattern('database.'); // only intercept database. paths ``` **Example** ```javascript // ESM usage via slothlet API (inside async function) async function example() { const { default: slothlet } = await import("@cldmv/slothlet"); const api = await slothlet({ base: './api', hook: true }); api.slothlet.hook.enablePattern('database.'); } ``` **Example** ```javascript // CJS usage via slothlet API (top-level) let slothlet; (async () => { ({ slothlet } = await import("@cldmv/slothlet")); const api = await slothlet({ base: './api', hook: true }); api.slothlet.hook.enablePattern('database.'); })(); ``` **Example** ```javascript // CJS usage via slothlet API (inside async function) const slothlet = require("@cldmv/slothlet"); const api = await slothlet({ base: './api', hook: true }); api.slothlet.hook.enablePattern('database.*'); ``` * * * #### api.slothlet.hook.list([filter]) ⇒ Object[] List registered hooks matching a filter. **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) | Param | Type | Description | | --- | --- | --- | | [filter] | Object | | **Returns**: Object[] **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api', hook: true }); const allHooks = api.slothlet.hook.list(); const beforeHooks = api.slothlet.hook.list({ type: 'before' }); ``` **Example** ```javascript // ESM usage via slothlet API (inside async function) async function example() { const { default: slothlet } = await import("@cldmv/slothlet"); const api = await slothlet({ base: './api', hook: true }); const allHooks = api.slothlet.hook.list(); const beforeHooks = api.slothlet.hook.list({ type: 'before' }); } ``` **Example** ```javascript // CJS usage via slothlet API (top-level) let slothlet; (async () => { ({ slothlet } = await import("@cldmv/slothlet")); const api = await slothlet({ base: './api', hook: true }); const allHooks = api.slothlet.hook.list(); const beforeHooks = api.slothlet.hook.list({ type: 'before' }); })(); ``` **Example** ```javascript // CJS usage via slothlet API (inside async function) const slothlet = require("@cldmv/slothlet"); const api = await slothlet({ base: './api', hook: true }); const allHooks = api.slothlet.hook.list(); const beforeHooks = api.slothlet.hook.list({ type: 'before' }); ``` * * * #### api.slothlet.hook.off(idOrFilter) ⇒ void Remove hooks by ID or filter object (v2 alias for remove()). **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) | Param | Type | Description | | --- | --- | --- | | idOrFilter | string\|Object | | **Returns**: void **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api', hook: true }); const hookId = api.slothlet.hook.on('math.:before', handler); api.slothlet.hook.off(hookId); // remove by ID api.slothlet.hook.off({ type: 'after' }); // remove by filter ``` **Example** ```javascript // ESM usage via slothlet API (inside async function) async function example() { const { default: slothlet } = await import("@cldmv/slothlet"); const api = await slothlet({ base: './api', hook: true }); const hookId = api.slothlet.hook.on('math.:before', handler); api.slothlet.hook.off(hookId); // remove by ID api.slothlet.hook.off({ type: 'after' }); // remove by filter } ``` **Example** ```javascript // CJS usage via slothlet API (top-level) let slothlet; (async () => { ({ slothlet } = await import("@cldmv/slothlet")); const api = await slothlet({ base: './api', hook: true }); const hookId = api.slothlet.hook.on('math.:before', handler); api.slothlet.hook.off(hookId); // remove by ID api.slothlet.hook.off({ type: 'after' }); // remove by filter })(); ``` **Example** ```javascript // CJS usage via slothlet API (inside async function) const slothlet = require("@cldmv/slothlet"); const api = await slothlet({ base: './api', hook: true }); const hookId = api.slothlet.hook.on('math.:before', handler); api.slothlet.hook.off(hookId); // remove by ID api.slothlet.hook.off({ type: 'after' }); // remove by filter ``` * * * #### api.slothlet.hook.on(typePattern, handler, [options]) ⇒ string Register a hook handler for a path-then-type pattern (e.g. "math.*:before"; the legacy "before:math.*" form is deprecated). **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) | Param | Type | Description | | --- | --- | --- | | typePattern | string | | | handler | function | | | [options] | Object | | **Returns**: string **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api', hook: true }); const hookId = api.slothlet.hook.on('math.:before', ({ args }) => { console.log('math called with', args); }); ``` **Example** ```javascript // ESM usage via slothlet API (inside async function) async function example() { const { default: slothlet } = await import("@cldmv/slothlet"); const api = await slothlet({ base: './api', hook: true }); const hookId = api.slothlet.hook.on('math.:before', ({ args }) => { console.log('math called with', args); }); } ``` **Example** ```javascript // CJS usage via slothlet API (top-level) let slothlet; (async () => { ({ slothlet } = await import("@cldmv/slothlet")); const api = await slothlet({ base: './api', hook: true }); const hookId = api.slothlet.hook.on('math.:before', ({ args }) => { console.log('math called with', args); }); })(); ``` **Example** ```javascript // CJS usage via slothlet API (inside async function) const slothlet = require("@cldmv/slothlet"); const api = await slothlet({ base: './api', hook: true }); const hookId = api.slothlet.hook.on('math.:before', ({ args }) => { console.log('math called with', args); }); ``` * * * #### api.slothlet.hook.pin.enable() ⇒ boolean Enforce hook pinning: a module hook's lockCaller: false is ignored (force-pinned). Host-only. **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) **Returns**: boolean **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api', hook: true }); api.slothlet.hook.pin.enable(); // force-pin module hooks (host only) ``` * * * #### api.slothlet.hook.pin.disable() ⇒ boolean Stop enforcing hook pinning: permit a per-registration lockCaller: false on module hooks. Host-only. **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) **Returns**: boolean **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api', hook: true }); api.slothlet.hook.pin.disable(); // permit unpinned module hooks (host only) ``` * * * #### api.slothlet.hook.remove([filter]) ⇒ void Remove hooks matching a filter (id, type, pattern). **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) | Param | Type | Description | | --- | --- | --- | | [filter] | Object | | **Returns**: void **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api', hook: true }); api.slothlet.hook.remove({ type: 'before', pattern: 'math.' }); ``` **Example** ```javascript // ESM usage via slothlet API (inside async function) async function example() { const { default: slothlet } = await import("@cldmv/slothlet"); const api = await slothlet({ base: './api', hook: true }); api.slothlet.hook.remove({ type: 'before', pattern: 'math.' }); } ``` **Example** ```javascript // CJS usage via slothlet API (top-level) let slothlet; (async () => { ({ slothlet } = await import("@cldmv/slothlet")); const api = await slothlet({ base: './api', hook: true }); api.slothlet.hook.remove({ type: 'before', pattern: 'math.' }); })(); ``` **Example** ```javascript // CJS usage via slothlet API (inside async function) const slothlet = require("@cldmv/slothlet"); const api = await slothlet({ base: './api', hook: true }); api.slothlet.hook.remove({ type: 'before', pattern: 'math.' }); ``` * * * #### api.slothlet.hook.resetPatternFilter() ⇒ void Reset the runtime global path filter back to the configured hook.pattern default (fully unrestricted if that default was "**"). **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) **Returns**: void **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api', hook: 'database.' }); api.slothlet.hook.enablePattern('cache.'); api.slothlet.hook.resetPatternFilter(); // back to database.* only ``` **Example** ```javascript // ESM usage via slothlet API (inside async function) async function example() { const { default: slothlet } = await import("@cldmv/slothlet"); const api = await slothlet({ base: './api', hook: 'database.' }); api.slothlet.hook.resetPatternFilter(); } ``` **Example** ```javascript // CJS usage via slothlet API (top-level) let slothlet; (async () => { ({ slothlet } = await import("@cldmv/slothlet")); const api = await slothlet({ base: './api', hook: 'database.' }); api.slothlet.hook.resetPatternFilter(); })(); ``` **Example** ```javascript // CJS usage via slothlet API (inside async function) const slothlet = require("@cldmv/slothlet"); const api = await slothlet({ base: './api', hook: 'database.*' }); api.slothlet.hook.resetPatternFilter(); ``` * * * #### api.slothlet.lifecycle.off(event, handler) ⇒ void Unsubscribe a handler from a lifecycle event. **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) | Param | Type | Description | | --- | --- | --- | | event | string | | | handler | function | | **Returns**: void **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api' }); const handler = () => console.log('shutdown'); api.slothlet.lifecycle.on('shutdown', handler); api.slothlet.lifecycle.off('shutdown', handler); ``` **Example** ```javascript // ESM usage via slothlet API (inside async function) async function example() { const { default: slothlet } = await import("@cldmv/slothlet"); const api = await slothlet({ base: './api' }); const handler = () => console.log('shutdown'); api.slothlet.lifecycle.on('shutdown', handler); api.slothlet.lifecycle.off('shutdown', handler); } ``` **Example** ```javascript // CJS usage via slothlet API (top-level) let slothlet; (async () => { ({ slothlet } = await import("@cldmv/slothlet")); const api = await slothlet({ base: './api' }); const handler = () => console.log('shutdown'); api.slothlet.lifecycle.on('shutdown', handler); api.slothlet.lifecycle.off('shutdown', handler); })(); ``` **Example** ```javascript // CJS usage via slothlet API (inside async function) const slothlet = require("@cldmv/slothlet"); const api = await slothlet({ base: './api' }); const handler = () => console.log('shutdown'); api.slothlet.lifecycle.on('shutdown', handler); api.slothlet.lifecycle.off('shutdown', handler); ``` * * * #### api.slothlet.lifecycle.on(event, handler) ⇒ void Subscribe to a lifecycle event (e.g. "materialized:complete"). **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) | Param | Type | Description | | --- | --- | --- | | event | string | | | handler | function | | **Returns**: void **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api' }); api.slothlet.lifecycle.on('shutdown', () => { console.log('Slothlet is shutting down'); }); ``` **Example** ```javascript // ESM usage via slothlet API (inside async function) async function example() { const { default: slothlet } = await import("@cldmv/slothlet"); const api = await slothlet({ base: './api' }); api.slothlet.lifecycle.on('shutdown', () => { console.log('Slothlet is shutting down'); }); } ``` **Example** ```javascript // CJS usage via slothlet API (top-level) let slothlet; (async () => { ({ slothlet } = await import("@cldmv/slothlet")); const api = await slothlet({ base: './api' }); api.slothlet.lifecycle.on('shutdown', () => { console.log('Slothlet is shutting down'); }); })(); ``` **Example** ```javascript // CJS usage via slothlet API (inside async function) const slothlet = require("@cldmv/slothlet"); const api = await slothlet({ base: './api' }); api.slothlet.lifecycle.on('shutdown', () => { console.log('Slothlet is shutting down'); }); ``` * * * #### api.slothlet.materialize.get() ⇒ Object Get current materialization statistics ({ total, materialized, remaining, percentage }). **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) **Returns**: Object **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api', mode: 'lazy' }); const stats = api.slothlet.materialize.get(); // { total: 5, materialized: 3, remaining: 2, percentage: 60 } ``` **Example** ```javascript // ESM usage via slothlet API (inside async function) async function example() { const { default: slothlet } = await import("@cldmv/slothlet"); const api = await slothlet({ base: './api', mode: 'lazy' }); const stats = api.slothlet.materialize.get(); // { total: 5, materialized: 3, remaining: 2, percentage: 60 } } ``` **Example** ```javascript // CJS usage via slothlet API (top-level) let slothlet; (async () => { ({ slothlet } = await import("@cldmv/slothlet")); const api = await slothlet({ base: './api', mode: 'lazy' }); const stats = api.slothlet.materialize.get(); // { total: 5, materialized: 3, remaining: 2, percentage: 60 } })(); ``` **Example** ```javascript // CJS usage via slothlet API (inside async function) const slothlet = require("@cldmv/slothlet"); const api = await slothlet({ base: './api', mode: 'lazy' }); const stats = api.slothlet.materialize.get(); // { total: 5, materialized: 3, remaining: 2, percentage: 60 } ``` * * * #### api.slothlet.materialize.wait() ⇒ Promise.<void> Returns a Promise that resolves when all lazy folders are fully materialized. **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) **Returns**: Promise.<void> **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api', mode: 'lazy' }); await api.slothlet.materialize.wait(); // resolves when all lazy modules are loaded ``` **Example** ```javascript // ESM usage via slothlet API (inside async function) async function example() { const { default: slothlet } = await import("@cldmv/slothlet"); const api = await slothlet({ base: './api', mode: 'lazy' }); await api.slothlet.materialize.wait(); // resolves when all lazy modules are loaded } ``` **Example** ```javascript // CJS usage via slothlet API (top-level) let slothlet; (async () => { ({ slothlet } = await import("@cldmv/slothlet")); const api = await slothlet({ base: './api', mode: 'lazy' }); await api.slothlet.materialize.wait(); // resolves when all lazy modules are loaded })(); ``` **Example** ```javascript // CJS usage via slothlet API (inside async function) const slothlet = require("@cldmv/slothlet"); const api = await slothlet({ base: './api', mode: 'lazy' }); await api.slothlet.materialize.wait(); // resolves when all lazy modules are loaded ``` * * * #### api.slothlet.metadata.caller() ⇒ Object|null Get metadata for the function that invoked the current one (runtime-injected). **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) **Returns**: Object|null **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api' }); // Inside an API module, get metadata of the calling function: const callerMeta = api.slothlet.metadata.caller(); // null if no caller ``` **Example** ```javascript // ESM usage via slothlet API (inside async function) async function example() { const { default: slothlet } = await import("@cldmv/slothlet"); const api = await slothlet({ base: './api' }); // Inside an API module, get metadata of the calling function: const callerMeta = api.slothlet.metadata.caller(); // null if no caller } ``` **Example** ```javascript // CJS usage via slothlet API (top-level) let slothlet; (async () => { ({ slothlet } = await import("@cldmv/slothlet")); const api = await slothlet({ base: './api' }); // Inside an API module, get metadata of the calling function: const callerMeta = api.slothlet.metadata.caller(); // null if no caller })(); ``` **Example** ```javascript // CJS usage via slothlet API (inside async function) const slothlet = require("@cldmv/slothlet"); const api = await slothlet({ base: './api' }); // Inside an API module, get metadata of the calling function: const callerMeta = api.slothlet.metadata.caller(); // null if no caller ``` * * * #### api.slothlet.metadata.get(fn) ⇒ Object Get metadata for a specific function reference. **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) | Param | Type | Description | | --- | --- | --- | | fn | function | | **Returns**: Object **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api' }); api.slothlet.metadata.set(api.math.add, 'label', 'Addition'); const meta = api.slothlet.metadata.get(api.math.add); // { label: 'Addition' } ``` **Example** ```javascript // ESM usage via slothlet API (inside async function) async function example() { const { default: slothlet } = await import("@cldmv/slothlet"); const api = await slothlet({ base: './api' }); api.slothlet.metadata.set(api.math.add, 'label', 'Addition'); const meta = api.slothlet.metadata.get(api.math.add); // { label: 'Addition' } } ``` **Example** ```javascript // CJS usage via slothlet API (top-level) let slothlet; (async () => { ({ slothlet } = await import("@cldmv/slothlet")); const api = await slothlet({ base: './api' }); api.slothlet.metadata.set(api.math.add, 'label', 'Addition'); const meta = api.slothlet.metadata.get(api.math.add); // { label: 'Addition' } })(); ``` **Example** ```javascript // CJS usage via slothlet API (inside async function) const slothlet = require("@cldmv/slothlet"); const api = await slothlet({ base: './api' }); api.slothlet.metadata.set(api.math.add, 'label', 'Addition'); const meta = api.slothlet.metadata.get(api.math.add); // { label: 'Addition' } ``` * * * #### api.slothlet.metadata.remove(fn, [key]) ⇒ void Remove per-function metadata (all keys or a specific key). **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) | Param | Type | Description | | --- | --- | --- | | fn | function | | | [key] | string | | **Returns**: void **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api' }); api.slothlet.metadata.set(api.math.add, 'label', 'Addition'); api.slothlet.metadata.remove(api.math.add, 'label'); // remove key api.slothlet.metadata.remove(api.math.add); // remove all ``` **Example** ```javascript // ESM usage via slothlet API (inside async function) async function example() { const { default: slothlet } = await import("@cldmv/slothlet"); const api = await slothlet({ base: './api' }); api.slothlet.metadata.set(api.math.add, 'label', 'Addition'); api.slothlet.metadata.remove(api.math.add, 'label'); // remove key api.slothlet.metadata.remove(api.math.add); // remove all } ``` **Example** ```javascript // CJS usage via slothlet API (top-level) let slothlet; (async () => { ({ slothlet } = await import("@cldmv/slothlet")); const api = await slothlet({ base: './api' }); api.slothlet.metadata.set(api.math.add, 'label', 'Addition'); api.slothlet.metadata.remove(api.math.add, 'label'); // remove key api.slothlet.metadata.remove(api.math.add); // remove all })(); ``` **Example** ```javascript // CJS usage via slothlet API (inside async function) const slothlet = require("@cldmv/slothlet"); const api = await slothlet({ base: './api' }); api.slothlet.metadata.set(api.math.add, 'label', 'Addition'); api.slothlet.metadata.remove(api.math.add, 'label'); // remove key api.slothlet.metadata.remove(api.math.add); // remove all ``` * * * #### api.slothlet.metadata.getFor(pathOrModuleId) ⇒ Object Get merged user metadata for an API path or moduleID. Walks root-to-leaf so descendants inherit ancestor entries automatically. Returns an empty object when no metadata is registered for the path. The returned object is not frozen — callers MUST NOT mutate it, since modifications would affect the live metadata store. Used internally by the module discovery system to round-trip the per-module manifest stored at the mount point under the _module key. **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) | Param | Type | Description | | --- | --- | --- | | pathOrModuleId | string | | **Returns**: Object **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api' }); await api.slothlet.api.modules.addDiscovered({ scanRoot: process.cwd() }); const meta = api.slothlet.metadata.getFor('drivers.opensearch'); console.log(meta._module?.manifest); // { schemaVersion: 1, name: '@org/foo', version: '1.4.2', ... } ``` * * * #### api.slothlet.metadata.removeFor(pathOrModuleId, [key]) ⇒ void Remove path-level metadata for a given API path or moduleID. **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) | Param | Type | Description | | --- | --- | --- | | pathOrModuleId | string | | | [key] | string\|Array.<string> | | **Returns**: void **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api' }); api.slothlet.metadata.removeFor('math', 'label'); // remove 'label' from all math functions api.slothlet.metadata.removeFor('math'); // remove all metadata ``` **Example** ```javascript // ESM usage via slothlet API (inside async function) async function example() { const { default: slothlet } = await import("@cldmv/slothlet"); const api = await slothlet({ base: './api' }); api.slothlet.metadata.removeFor('math', 'label'); // remove 'label' from all math functions api.slothlet.metadata.removeFor('math'); // remove all metadata } ``` **Example** ```javascript // CJS usage via slothlet API (top-level) let slothlet; (async () => { ({ slothlet } = await import("@cldmv/slothlet")); const api = await slothlet({ base: './api' }); api.slothlet.metadata.removeFor('math', 'label'); // remove 'label' from all math functions api.slothlet.metadata.removeFor('math'); // remove all metadata })(); ``` **Example** ```javascript // CJS usage via slothlet API (inside async function) const slothlet = require("@cldmv/slothlet"); const api = await slothlet({ base: './api' }); api.slothlet.metadata.removeFor('math', 'label'); // remove 'label' from all math functions api.slothlet.metadata.removeFor('math'); // remove all metadata ``` * * * #### api.slothlet.metadata.self() ⇒ Object|null Get metadata for the currently-executing API function (runtime-injected). **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) **Returns**: Object|null **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api' }); api.slothlet.metadata.set(api.math.add, 'label', 'Addition'); // Inside api.math.add, get its own metadata: const ownMeta = api.slothlet.metadata.self(); // { label: 'Addition' } ``` **Example** ```javascript // ESM usage via slothlet API (inside async function) async function example() { const { default: slothlet } = await import("@cldmv/slothlet"); const api = await slothlet({ base: './api' }); api.slothlet.metadata.set(api.math.add, 'label', 'Addition'); // Inside api.math.add, get its own metadata: const ownMeta = api.slothlet.metadata.self(); // { label: 'Addition' } } ``` **Example** ```javascript // CJS usage via slothlet API (top-level) let slothlet; (async () => { ({ slothlet } = await import("@cldmv/slothlet")); const api = await slothlet({ base: './api' }); api.slothlet.metadata.set(api.math.add, 'label', 'Addition'); // Inside api.math.add, get its own metadata: const ownMeta = api.slothlet.metadata.self(); // { label: 'Addition' } })(); ``` **Example** ```javascript // CJS usage via slothlet API (inside async function) const slothlet = require("@cldmv/slothlet"); const api = await slothlet({ base: './api' }); api.slothlet.metadata.set(api.math.add, 'label', 'Addition'); // Inside api.math.add, get its own metadata: const ownMeta = api.slothlet.metadata.self(); // { label: 'Addition' } ``` * * * #### api.slothlet.metadata.set(fn, key, value) ⇒ void Set per-function metadata by direct function reference. **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) | Param | Type | Description | | --- | --- | --- | | fn | function | | | key | string | | | value | * | | **Returns**: void **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api' }); api.slothlet.metadata.set(api.math.add, 'label', 'Addition'); api.slothlet.metadata.set(api.math.add, 'tags', ['math', 'util']); ``` **Example** ```javascript // ESM usage via slothlet API (inside async function) async function example() { const { default: slothlet } = await import("@cldmv/slothlet"); const api = await slothlet({ base: './api' }); api.slothlet.metadata.set(api.math.add, 'label', 'Addition'); api.slothlet.metadata.set(api.math.add, 'tags', ['math', 'util']); } ``` **Example** ```javascript // CJS usage via slothlet API (top-level) let slothlet; (async () => { ({ slothlet } = await import("@cldmv/slothlet")); const api = await slothlet({ base: './api' }); api.slothlet.metadata.set(api.math.add, 'label', 'Addition'); api.slothlet.metadata.set(api.math.add, 'tags', ['math', 'util']); })(); ``` **Example** ```javascript // CJS usage via slothlet API (inside async function) const slothlet = require("@cldmv/slothlet"); const api = await slothlet({ base: './api' }); api.slothlet.metadata.set(api.math.add, 'label', 'Addition'); api.slothlet.metadata.set(api.math.add, 'tags', ['math', 'util']); ``` * * * #### api.slothlet.metadata.setFor(pathOrModuleId, keyOrObj, [value]) ⇒ void Set metadata for all functions reachable under an API path or moduleID. **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) | Param | Type | Description | | --- | --- | --- | | pathOrModuleId | string | | | keyOrObj | string\|Object | | | [value] | * | | **Returns**: void **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api' }); api.slothlet.metadata.setFor('math', 'category', 'utilities'); api.slothlet.metadata.setFor('math', { category: 'utils', version: '1.0' }); ``` **Example** ```javascript // ESM usage via slothlet API (inside async function) async function example() { const { default: slothlet } = await import("@cldmv/slothlet"); const api = await slothlet({ base: './api' }); api.slothlet.metadata.setFor('math', 'category', 'utilities'); api.slothlet.metadata.setFor('math', { category: 'utils', version: '1.0' }); } ``` **Example** ```javascript // CJS usage via slothlet API (top-level) let slothlet; (async () => { ({ slothlet } = await import("@cldmv/slothlet")); const api = await slothlet({ base: './api' }); api.slothlet.metadata.setFor('math', 'category', 'utilities'); api.slothlet.metadata.setFor('math', { category: 'utils', version: '1.0' }); })(); ``` **Example** ```javascript // CJS usage via slothlet API (inside async function) const slothlet = require("@cldmv/slothlet"); const api = await slothlet({ base: './api' }); api.slothlet.metadata.setFor('math', 'category', 'utilities'); api.slothlet.metadata.setFor('math', { category: 'utils', version: '1.0' }); ``` * * * #### api.slothlet.metadata.setGlobal(key, value) ⇒ void Set global metadata applied to every function in the instance. **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) | Param | Type | Description | | --- | --- | --- | | key | string | | | value | * | | **Returns**: void **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api' }); api.slothlet.metadata.setGlobal('version', '2.0'); // Every function now has metadata: { version: '2.0' } ``` **Example** ```javascript // ESM usage via slothlet API (inside async function) async function example() { const { default: slothlet } = await import("@cldmv/slothlet"); const api = await slothlet({ base: './api' }); api.slothlet.metadata.setGlobal('version', '2.0'); // Every function now has metadata: { version: '2.0' } } ``` **Example** ```javascript // CJS usage via slothlet API (top-level) let slothlet; (async () => { ({ slothlet } = await import("@cldmv/slothlet")); const api = await slothlet({ base: './api' }); api.slothlet.metadata.setGlobal('version', '2.0'); // Every function now has metadata: { version: '2.0' } })(); ``` **Example** ```javascript // CJS usage via slothlet API (inside async function) const slothlet = require("@cldmv/slothlet"); const api = await slothlet({ base: './api' }); api.slothlet.metadata.setGlobal('version', '2.0'); // Every function now has metadata: { version: '2.0' } ``` * * * #### api.slothlet.owner.get(apiPath) ⇒ Object Get ownership info for a specific API path. **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) | Param | Type | Description | | --- | --- | --- | | apiPath | string | | **Returns**: Object **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api' }); const info = api.slothlet.owner.get('math.add'); // { path: 'math.add', owners: Set { 'utils/math.mjs' } } ``` **Example** ```javascript // ESM usage via slothlet API (inside async function) async function example() { const { default: slothlet } = await import("@cldmv/slothlet"); const api = await slothlet({ base: './api' }); const info = api.slothlet.owner.get('math.add'); // { path: 'math.add', owners: Set { 'utils/math.mjs' } } } ``` **Example** ```javascript // CJS usage via slothlet API (top-level) let slothlet; (async () => { ({ slothlet } = await import("@cldmv/slothlet")); const api = await slothlet({ base: './api' }); const info = api.slothlet.owner.get('math.add'); // { path: 'math.add', owners: Set { 'utils/math.mjs' } } })(); ``` **Example** ```javascript // CJS usage via slothlet API (inside async function) const slothlet = require("@cldmv/slothlet"); const api = await slothlet({ base: './api' }); const info = api.slothlet.owner.get('math.add'); // { path: 'math.add', owners: Set { 'utils/math.mjs' } } ``` * * * #### api.slothlet.ownership.get(apiPath) ⇒ Set.<string> Get the set of moduleIDs that own a given API path. **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) | Param | Type | Description | | --- | --- | --- | | apiPath | string | | **Returns**: Set.<string> **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api' }); const owners = api.slothlet.ownership.get('math.add'); // Set { 'utils/math.mjs' } ``` **Example** ```javascript // ESM usage via slothlet API (inside async function) async function example() { const { default: slothlet } = await import("@cldmv/slothlet"); const api = await slothlet({ base: './api' }); const owners = api.slothlet.ownership.get('math.add'); // Set { 'utils/math.mjs' } } ``` **Example** ```javascript // CJS usage via slothlet API (top-level) let slothlet; (async () => { ({ slothlet } = await import("@cldmv/slothlet")); const api = await slothlet({ base: './api' }); const owners = api.slothlet.ownership.get('math.add'); // Set { 'utils/math.mjs' } })(); ``` **Example** ```javascript // CJS usage via slothlet API (inside async function) const slothlet = require("@cldmv/slothlet"); const api = await slothlet({ base: './api' }); const owners = api.slothlet.ownership.get('math.add'); // Set { 'utils/math.mjs' } ``` * * * #### api.slothlet.ownership.unregister(moduleID) ⇒ void Unregister a module from all ownership records. **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) | Param | Type | Description | | --- | --- | --- | | moduleID | string | | **Returns**: void **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api' }); await api.slothlet.api.remove('math'); api.slothlet.ownership.unregister('utils/math.mjs'); ``` **Example** ```javascript // ESM usage via slothlet API (inside async function) async function example() { const { default: slothlet } = await import("@cldmv/slothlet"); const api = await slothlet({ base: './api' }); await api.slothlet.api.remove('math'); api.slothlet.ownership.unregister('utils/math.mjs'); } ``` **Example** ```javascript // CJS usage via slothlet API (top-level) let slothlet; (async () => { ({ slothlet } = await import("@cldmv/slothlet")); const api = await slothlet({ base: './api' }); await api.slothlet.api.remove('math'); api.slothlet.ownership.unregister('utils/math.mjs'); })(); ``` **Example** ```javascript // CJS usage via slothlet API (inside async function) const slothlet = require("@cldmv/slothlet"); const api = await slothlet({ base: './api' }); await api.slothlet.api.remove('math'); api.slothlet.ownership.unregister('utils/math.mjs'); ``` * * * #### api.slothlet.permissions.control.enable() ⇒ void Enable permission enforcement globally. **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) **Returns**: void **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api', permissions: { defaultPolicy: 'allow' } }); api.slothlet.permissions.control.enable(); ``` * * * #### api.slothlet.permissions.control.disable() ⇒ void Disable permission enforcement globally (all calls allowed). **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) **Returns**: void **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api', permissions: { defaultPolicy: 'deny' } }); api.slothlet.permissions.control.disable(); ``` * * * #### api.slothlet.permissions.control.readGating(value) ⇒ void Enable or disable read-level permission gating at runtime. Throws INVALID_ARGUMENT for a non-boolean argument. **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) | Param | Type | Description | | --- | --- | --- | | value | boolean | | **Returns**: void **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api', permissions: { defaultPolicy: 'allow' } }); api.slothlet.permissions.control.readGating(false); // stop gating reads api.slothlet.permissions.control.readGating(true); // resume ``` * * * #### api.slothlet.versioning.list(logicalPath) ⇒ {versions: object, default: string|null}|undefined List all registered versions for a logical API path. Returns undefined if the path has no registered versions or if versioning has not yet been used. **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) | Param | Type | Description | | --- | --- | --- | | logicalPath | string | | **Returns**: {versions: object, default: string|null}|undefined **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api', versionDispatcher: "version" }); await api.slothlet.api.add('auth', './api/v1', {}, { version: 'v1', default: true }); const info = api.slothlet.versioning.list('auth'); if (info) console.log(info.default); // "v1" ``` * * * #### api.slothlet.versioning.setDefault(logicalPath, versionTag) ⇒ void Override the default version for a logical API path at runtime. If no versions are registered for the path, this call has no effect until versioning data exists. **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) | Param | Type | Description | | --- | --- | --- | | logicalPath | string | | | versionTag | string | | **Returns**: void **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api', versionDispatcher: "version" }); await api.slothlet.api.add('auth', './api/v1', {}, { version: 'v1' }); await api.slothlet.api.add('auth', './api/v2', {}, { version: 'v2' }); api.slothlet.versioning.setDefault('auth', 'v1'); ``` * * * #### api.slothlet.versioning.unregister(logicalPath, versionTag) ⇒ Promise.<boolean> Unregister a specific version from a logical API path. Removes the versioned namespace (vX.path) and updates or tears down the dispatcher. If the logical path/version is not registered, this resolves without removing anything. **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) | Param | Type | Description | | --- | --- | --- | | logicalPath | string | | | versionTag | string | | **Returns**: Promise.<boolean> **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api', versionDispatcher: "version" }); await api.slothlet.api.add('auth', './api/v1', {}, { version: 'v1' }); await api.slothlet.api.add('auth', './api/v2', {}, { version: 'v2' }); const removed = await api.slothlet.versioning.unregister('auth', 'v2'); // true ``` * * * #### api.slothlet.versioning.getVersionMetadata(logicalPath, versionTag) ⇒ object|undefined Retrieve the VersionManager-only metadata stored at registration time via versionConfig.metadata. Returns undefined if the path or version is not registered, or if versioning has not yet been used. **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) | Param | Type | Description | | --- | --- | --- | | logicalPath | string | | | versionTag | string | | **Returns**: object|undefined **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api', versionDispatcher: "version" }); await api.slothlet.api.add('auth', './api/v1', {}, { version: 'v1', metadata: { stable: true } }); const meta = api.slothlet.versioning.getVersionMetadata('auth', 'v1'); // { stable: true, version: 'v1', logicalPath: 'auth' } ``` * * * #### api.slothlet.versioning.setVersionMetadata(logicalPath, versionTag, patch) ⇒ void Patch (merge) the VersionManager-only metadata for a registered version at runtime. The injected version and logicalPath keys always win over supplied patch fields. Throws VERSION_NOT_FOUND if the path or version is not registered. **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) | Param | Type | Description | | --- | --- | --- | | logicalPath | string | | | versionTag | string | | | patch | object | | **Returns**: void **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api', versionDispatcher: "version" }); await api.slothlet.api.add('auth', './api/v1', {}, { version: 'v1' }); api.slothlet.versioning.setVersionMetadata('auth', 'v1', { stable: true }); ``` * * * #### api.slothlet.lockCaller(fn) ⇒ function Freeze the registering module's caller identity onto a callback. The returned wrapper overrides only the caller identity when invoked; request-scoped context stays live. In async runtime mode the pinned identity propagates through AsyncLocalStorage for the callback's full async lifetime. In live runtime mode identity is pinned only for the synchronous portion — once fn returns its promise the live context is restored, so an async callback that awaits before calling self.* resumes with no slothlet caller at all (an identity check sees unknown); use async runtime mode for async hooks (e.g. Fastify addHook) that must keep identity past the first await. **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) | Param | Type | Description | | --- | --- | --- | | fn | function | | **Returns**: function **Example** ```javascript // Inside a module's init() server.addHook("onRequest", self.slothlet.lockCaller(handler)); ``` * * * #### api.slothlet.bind(fn) ⇒ function Freeze the entire async context onto a callback at registration time (convenience re-export of AsyncResource.bind). Unlike lockCaller, which overrides only caller identity and leaves request-scoped context live, bind freezes every AsyncLocalStorage, including slothlet's caller and context. Meaningful in async runtime mode; degrades to non-slothlet ALS context in live mode. **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) | Param | Type | Description | | --- | --- | --- | | fn | function | | **Returns**: function **Example** ```javascript // Inside a module's init() server.addHook("onRequest", self.slothlet.bind(handler)); ``` * * * #### api.slothlet.reload([options]) ⇒ Promise.<void> Reload the entire instance (re-scans the directory and recreates all module references). Accepts { keepInstanceID: boolean }. **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) | Param | Type | Description | | --- | --- | --- | | [options] | Object | | **Returns**: Promise.<void> **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api' }); await api.slothlet.reload(); // full reload ``` **Example** ```javascript // ESM usage via slothlet API (inside async function) async function example() { const { default: slothlet } = await import("@cldmv/slothlet"); const api = await slothlet({ base: './api' }); await api.slothlet.reload(); // full reload } ``` **Example** ```javascript // CJS usage via slothlet API (top-level) let slothlet; (async () => { ({ slothlet } = await import("@cldmv/slothlet")); const api = await slothlet({ base: './api' }); await api.slothlet.reload(); // full reload })(); ``` **Example** ```javascript // CJS usage via slothlet API (inside async function) const slothlet = require("@cldmv/slothlet"); const api = await slothlet({ base: './api' }); await api.slothlet.reload(); // full reload ``` * * * #### api.slothlet.run(contextData, callback, args) ⇒ * Execute a callback with isolated per-request context data. Convenience alias for slothlet.context.run(). **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) | Param | Type | Description | | --- | --- | --- | | contextData | Object | | | callback | function | | | args | * | | **Returns**: * **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api' }); const result = await api.slothlet.run({ userId: 42 }, async () => { return api.myModule.getUser(); }); ``` **Example** ```javascript // ESM usage via slothlet API (inside async function) async function example() { const { default: slothlet } = await import("@cldmv/slothlet"); const api = await slothlet({ base: './api' }); const result = await api.slothlet.run({ userId: 42 }, async () => { return api.myModule.getUser(); }); } ``` **Example** ```javascript // CJS usage via slothlet API (top-level) let slothlet; (async () => { ({ slothlet } = await import("@cldmv/slothlet")); const api = await slothlet({ base: './api' }); const result = await api.slothlet.run({ userId: 42 }, async () => { return api.myModule.getUser(); }); })(); ``` **Example** ```javascript // CJS usage via slothlet API (inside async function) const slothlet = require("@cldmv/slothlet"); const api = await slothlet({ base: './api' }); const result = await api.slothlet.run({ userId: 42 }, async () => { return api.myModule.getUser(); }); ``` * * * #### api.slothlet.scope(options) ⇒ * Execute a function with full structured per-request context options. Convenience alias for slothlet.context.scope(). **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) | Param | Type | Description | | --- | --- | --- | | options | Object | | **Returns**: * **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api' }); const result = await api.slothlet.scope({ context: { userId: 42 }, fn: async () => api.myModule.getUser() }); ``` **Example** ```javascript // ESM usage via slothlet API (inside async function) async function example() { const { default: slothlet } = await import("@cldmv/slothlet"); const api = await slothlet({ base: './api' }); const result = await api.slothlet.scope({ context: { userId: 42 }, fn: async () => api.myModule.getUser() }); } ``` **Example** ```javascript // CJS usage via slothlet API (top-level) let slothlet; (async () => { ({ slothlet } = await import("@cldmv/slothlet")); const api = await slothlet({ base: './api' }); const result = await api.slothlet.scope({ context: { userId: 42 }, fn: async () => api.myModule.getUser() }); })(); ``` **Example** ```javascript // CJS usage via slothlet API (inside async function) const slothlet = require("@cldmv/slothlet"); const api = await slothlet({ base: './api' }); const result = await api.slothlet.scope({ context: { userId: 42 }, fn: async () => api.myModule.getUser() }); ``` * * * #### api.slothlet.shutdown() ⇒ Promise.<void> Shut down the instance and release all resources. **Kind**: function property of [SlothletAPI](#typedef_module_at_cldmv_slash_slothlet_SlothletAPI) **Returns**: Promise.<void> **Example** ```javascript // ESM usage via slothlet API import slothlet from "@cldmv/slothlet"; const api = await slothlet({ base: './api' }); await api.slothlet.shutdown(); ``` **Example** ```javascript // ESM usage via slothlet API (inside async function) async function example() { const { default: slothlet } = await import("@cldmv/slothlet"); const api = await slothlet({ base: './api' }); await api.slothlet.shutdown(); } ``` **Example** ```javascript // CJS usage via slothlet API (top-level) let slothlet; (async () => { ({ slothlet } = await import("@cldmv/slothlet")); const api = await slothlet({ base: './api' }); await api.slothlet.shutdown(); })(); ``` **Example** ```javascript // CJS usage via slothlet API (inside async function) const slothlet = require("@cldmv/slothlet"); const api = await slothlet({ base: './api' }); await api.slothlet.shutdown(); ``` * * * | Property | Type | Description | | --- | --- | --- | | slothlet | object | Built-in control namespace. All framework internals live here to avoid collisions with loaded modules. | | slothlet.env | Readonly.> | Frozen snapshot of `process.env` captured once at instance creation (before any module lifecycle runs). Immutable for the lifetime of the instance — reloads do NOT refresh it. When `env.include` is configured, only the listed keys are captured; otherwise, the full environment is snapshotted. | | slothlet.api | object | Runtime API mutation methods — availability controlled by `api.mutations` config option. | | slothlet.api.modules | object | Module discovery + mount sub-namespace. Composes subsystems shipped as separate npm packages (each with a `slothlet.module.json` manifest) into this api tree at runtime. Each method is typed as `Function` here; the detailed parameter / return shapes (`DiscoverOptions`, `DiscoverResult`, `AddModuleOptions`, `AddModulesOptions`, `MountResult`, `FailureEntry`) live in `docs/MODULE-DISCOVERY.md`, which also covers multi-version routing, error codes, and the `modules:*` lifecycle events. | | slothlet.context | object | Per-request context helpers. | | [slothlet.diag] | object | Diagnostics namespace — only present when `diagnostics: true`. Do not enable in production. | | [slothlet.diag.caches] | object | Cache diagnostics sub-namespace. | | [slothlet.diag.context] | object | The `context` config value as passed to `slothlet()`. | | [slothlet.diag.hook] | object | Hook system diagnostics sub-namespace (present only when hooks are enabled). | | [slothlet.diag.owner] | object | Ownership sub-namespace for diagnostics. | | [slothlet.diag.reference] | object | The `reference` config value as passed to `slothlet()`. | | slothlet.hook | object | Hook registration surface — only present when the `hook` option is enabled. | | slothlet.hook.pin | object | Host-only runtime control over hook-pinning enforcement (mirrors `permissions.control`). "Host-only" is enforced by the built-in `slothlet.hook.**` permission deny baseline, so it only holds when the permission system is enabled — without permissions a module reaching the hook surface can toggle it. Force-pinning makes a module hook always run under its registering module's identity; an unpinned module hook is a permission-bypass vector. Enabled by default (config `hook.pin`). | | slothlet.hook.pin.enabled | boolean | Whether hook pinning is currently enforced (true = module hooks are force-pinned, the default). %%sig: boolean%% %%example: // ESM usage via slothlet API\|import slothlet from "@cldmv/slothlet";\|const api = await slothlet({ base: './api', hook: true });\|const enforced = api.slothlet.hook.pin.enabled;%% | | slothlet.lifecycle | object | Lifecycle event emitter. | | slothlet.materialize | object | Lazy materialization tracking (meaningful only when `mode: "lazy"`). | | slothlet.materialize.materialized | boolean | `true` once all lazy folders have been fully loaded. | | slothlet.metadata | object | Module metadata accessor. | | slothlet.owner | object | Direct path ownership accessor (shorthand for `slothlet.ownership`). | | slothlet.ownership | object | Module ownership registry. | | slothlet.permissions | object | Permission system surface — present whenever a `permissions` block is configured. Rule registration (`addRule`/`removeRule`), self/global introspection (`self.*`, `global.*`), and runtime control (`control.*`) live here. Only the `control` sub-namespace is typed in this typedef; the rule-management methods are documented in `docs/PERMISSIONS.md`. | | slothlet.permissions.control | object | Runtime control over permission enforcement. | | slothlet.permissions.control.enabled | boolean | Current permission-enforcement state. Exposed as a getter so descriptor-based reads remain permission-gated. %%sig: boolean%% %%example: // ESM usage via slothlet API\|import slothlet from "@cldmv/slothlet";\|const api = await slothlet({ base: './api', permissions: { defaultPolicy: 'allow' } });\|const on = api.slothlet.permissions.control.enabled;%% | | slothlet.permissions.control.readGatingEnabled | boolean | Current read-level gating state. `true` when terminal data-value property reads are permission-gated. Exposed as a getter so descriptor-based reads remain permission-gated. %%sig: boolean%% %%example: // ESM usage via slothlet API\|import slothlet from "@cldmv/slothlet";\|const api = await slothlet({ base: './api', permissions: { defaultPolicy: 'allow' } });\|const gated = api.slothlet.permissions.control.readGatingEnabled;%% | | slothlet.versioning | object | Runtime version management API. This namespace is always present on `api.slothlet`; before any module has been registered via `api.slothlet.api.add()` with a `versionConfig` argument, its methods return `undefined` where documented or otherwise have no effect until versioning data exists. | | [slothlet.reference] | object | The `reference` object from config, merged onto the root API and accessible here. | * * * ## @cldmv/slothlet/runtime >

Provides live bindings for use inside API module functions. Import the exports you need:

>
import { self, context, instanceID } from "@cldmv/slothlet/runtime";
> 
> > > > > > > > > > > > > > > > > > > > > > > > > >
ExportTypeDescription
selfobjectLive reference to the full Slothlet API proxy. Use to call sibling modules without import cycles.
contextobjectThe current ambient context object. Seeded at startup via config.context and persists across calls. api.slothlet.context.run() / .scope() can override it for the duration of a single call. Readable and writable.
instanceIDstringUnique identifier of the active Slothlet instance.
>

All three are lazy Proxy objects — they resolve to the correct runtime value at call time, > whether the instance uses "async" (AsyncLocalStorage) or "live" runtime mode.

> ## @cldmv/slothlet/typegen >

Loads a Slothlet API directory in eager + fast TypeScript mode, then writes a > .d.ts file describing the resulting API shape. Intended for users who want > editor-time type information for their API without running Slothlet in strict > mode at runtime.

>

The same logic is exposed three ways:

>
    >
  • As a function: import { generateTypes } from "@cldmv/slothlet/typegen"
  • >
  • As a CLI: npx slothlet typegen ./api ./types/api.d.ts MyApi
  • >
  • As a CLI with no args, falling back to the slothlet.typegen field in > the project's package.json.
  • >
>

Runtime is unaffected — the user runs this on demand (e.g. via prebuild or > predev scripts) and ships the generated .d.ts alongside (or instead of) > the source. Slothlet does NOT auto-regenerate types at load time.

> ## @cldmv/slothlet/helpers/generate-manifest >

Two entry points, both Node.js-only build-time utilities (they use node:fs / module > resolution and run in your build step, a Vite/Webpack plugin, or an Electron main process):

>
    >
  • generateBrowserAssets(apiDir, { slothletBase })the recommended one-call entry. > Returns { manifest, importmap }: the API-directory manifest and the importmap for > slothlet's own modules, so browser consumers never hand-roll the latter (see #123).
  • >
  • generateManifest(dir) — the lower-level primitive that returns just the API manifest > (the { files, directories } tree passed to slothlet({ manifest, resolveModuleSpecifier })).
  • >
>

Why two artifacts: slothlet loads API leaves at runtime, so their location is deferred to > the resolveModuleSpecifier callback (the manifest holds relative paths). slothlet's own > static imports are resolved by the browser before slothlet runs, so they must live in the > page's <script type="importmap"> — which is what importmap provides.

>

Manifest shape:

>
{
>   "files": [
>     { "path": "math.mjs", "name": "math", "fullName": "math.mjs" }
>   ],
>   "directories": [
>     {
>       "name": "utils",
>       "path": "utils",
>       "children": {
>         "files": [{ "path": "utils/format.mjs", "name": "format", "fullName": "format.mjs" }],
>         "directories": []
>       }
>     }
>   ]
> }
> 

> **Example** ```js // build.mjs — run this at build time in Node.js import { generateManifest } from "@cldmv/slothlet/helpers/generate-manifest"; import { writeFileSync } from "node:fs"; const manifest = await generateManifest("./src/api"); writeFileSync("./public/api-manifest.json", JSON.stringify(manifest, null, 2)); ``` **Example** ```js // app.js — use the manifest at runtime in the browser import manifest from "./public/api-manifest.json" assert { type: "json" }; import { slothlet } from "@cldmv/slothlet"; import { createManifestResolver } from "@cldmv/slothlet/helpers/manifest-resolver"; const api = await slothlet({ manifest, resolveModuleSpecifier: createManifestResolver(new URL("./api/", import.meta.url)) }); ``` ## @cldmv/slothlet/helpers/manifest-resolver >

createManifestResolver(base) produces a resolveModuleSpecifier function that > resolves manifest-relative file paths to absolute URLs using the standard > new URL(path, base) algorithm. This is the correct resolver for any deployment > where API modules are served from a known base URL (the vast majority of use cases).

>

This file has no Node.js-specific imports — it is safe to include in a browser > bundle directly. For the build-time generateManifest utility (which uses node:fs) > see @cldmv/slothlet/helpers/generate-manifest.

>

Typical browser workflow

>
Build time  →  generateManifest("./src/api")  →  api-manifest.json
> Bundle time →  import api-manifest.json
> Runtime     →  createManifestResolver(import.meta.url)  →  pass to slothlet()
> 

> **Example** ```js // API modules live next to the current module import { createManifestResolver } from "@cldmv/slothlet/helpers/manifest-resolver"; import manifest from "./api-manifest.json" assert { type: "json" }; import { slothlet } from "@cldmv/slothlet"; const api = await slothlet({ manifest, resolveModuleSpecifier: createManifestResolver(import.meta.url) }); ``` **Example** ```js // API modules live in a sub-directory relative to the current module import { createManifestResolver } from "@cldmv/slothlet/helpers/manifest-resolver"; const api = await slothlet({ manifest, resolveModuleSpecifier: createManifestResolver(new URL("./api/", import.meta.url)) }); ```