@cldmv/slothlet 2.5.5 → 2.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/README.md +59 -5
  2. package/dist/lib/helpers/als-eventemitter.mjs +5 -4
  3. package/dist/lib/helpers/api_builder.mjs +27 -13
  4. package/dist/lib/helpers/auto-wrap.mjs +4 -2
  5. package/dist/lib/helpers/instance-manager.mjs +111 -0
  6. package/dist/lib/helpers/multidefault.mjs +12 -2
  7. package/dist/lib/modes/slothlet_eager.mjs +1 -1
  8. package/dist/lib/modes/slothlet_lazy.mjs +48 -5
  9. package/dist/lib/runtime/runtime-asynclocalstorage.mjs +435 -0
  10. package/dist/lib/runtime/runtime-livebindings.mjs +298 -0
  11. package/dist/lib/runtime/runtime.mjs +152 -349
  12. package/dist/slothlet.mjs +97 -11
  13. package/index.cjs +30 -39
  14. package/index.mjs +45 -15
  15. package/package.json +17 -1
  16. package/types/dist/lib/helpers/als-eventemitter.d.mts +3 -3
  17. package/types/dist/lib/helpers/als-eventemitter.d.mts.map +1 -1
  18. package/types/dist/lib/helpers/api_builder.d.mts.map +1 -1
  19. package/types/dist/lib/helpers/auto-wrap.d.mts.map +1 -1
  20. package/types/dist/lib/helpers/instance-manager.d.mts +41 -0
  21. package/types/dist/lib/helpers/instance-manager.d.mts.map +1 -0
  22. package/types/dist/lib/helpers/multidefault.d.mts +8 -3
  23. package/types/dist/lib/helpers/multidefault.d.mts.map +1 -1
  24. package/types/dist/lib/modes/slothlet_lazy.d.mts.map +1 -1
  25. package/types/dist/lib/runtime/runtime-asynclocalstorage.d.mts +58 -0
  26. package/types/dist/lib/runtime/runtime-asynclocalstorage.d.mts.map +1 -0
  27. package/types/dist/lib/runtime/runtime-livebindings.d.mts +58 -0
  28. package/types/dist/lib/runtime/runtime-livebindings.d.mts.map +1 -0
  29. package/types/dist/lib/runtime/runtime.d.mts +8 -57
  30. package/types/dist/lib/runtime/runtime.d.mts.map +1 -1
  31. package/types/dist/slothlet.d.mts +17 -9
  32. package/types/dist/slothlet.d.mts.map +1 -1
package/README.md CHANGED
@@ -104,6 +104,12 @@ v2.0 represents a ground-up rewrite with enterprise-grade features:
104
104
  > [!TIP]
105
105
  > **📁 For comprehensive examples of API flattening, naming conventions, and function preservation patterns, see the test modules in [api_tests/](https://github.com/CLDMV/slothlet/blob/HEAD/api_tests) and their documentation in [docs/api_tests/](https://github.com/CLDMV/slothlet/blob/HEAD/docs/api_tests)**
106
106
 
107
+ > [!NOTE]
108
+ > **🔍 For detailed technical documentation on API transformation rules:**
109
+ >
110
+ > - **[API-RULES.md](https://github.com/CLDMV/slothlet/blob/HEAD/API-RULES.md)** - Verified API transformation rules with examples and test cases
111
+ > - **[API-RULES-CONDITIONS.md](https://github.com/CLDMV/slothlet/blob/HEAD/API-RULES-CONDITIONS.md)** - Complete technical reference of all conditional logic that controls API generation
112
+
107
113
  ### 🔗 **Advanced Binding System**
108
114
 
109
115
  - **Live Bindings**: Dynamic context and reference binding for runtime API mutation
@@ -193,9 +199,16 @@ const mixedResult = await api.interop.processData({ data: "test" }); // CJS+ESM
193
199
  ```javascript
194
200
  import slothlet from "@cldmv/slothlet";
195
201
 
196
- // Lazy mode with copy-left materialization (opt-in)
202
+ // Lazy mode with copy-left materialization
197
203
  const api = await slothlet({
198
- lazy: true,
204
+ mode: "lazy", // New preferred syntax
205
+ dir: "./api",
206
+ apiDepth: 3
207
+ });
208
+
209
+ // Or use legacy syntax (still supported)
210
+ const apiLegacy = await slothlet({
211
+ lazy: true, // Legacy syntax
199
212
  dir: "./api",
200
213
  apiDepth: 3
201
214
  });
@@ -214,7 +227,8 @@ import slothlet from "@cldmv/slothlet";
214
227
 
215
228
  const api = await slothlet({
216
229
  dir: "./api",
217
- lazy: false, // Loading strategy
230
+ mode: "eager", // New: Loading strategy (lazy/eager)
231
+ engine: "singleton", // New: Execution environment
218
232
  api_mode: "auto", // API structure behavior
219
233
  apiDepth: Infinity, // Directory traversal depth
220
234
  debug: false, // Enable verbose logging
@@ -334,15 +348,50 @@ Creates and loads an API instance with the specified configuration.
334
348
  | Option | Type | Default | Description |
335
349
  | ----------- | --------- | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
336
350
  | `dir` | `string` | `"api"` | Directory to load API modules from. Can be absolute or relative path. If relative, resolved from process.cwd(). |
337
- | `lazy` | `boolean` | `false` | Loading strategy - `true` for lazy loading (on-demand), `false` for eager loading (immediate) |
351
+ | `lazy` | `boolean` | `false` | **Legacy** loading strategy - `true` for lazy loading (on-demand), `false` for eager loading (immediate). Use `mode` option instead. |
352
+ | `mode` | `string` | - | **New** loading mode - `"lazy"` for on-demand loading, `"eager"` for immediate loading. Takes precedence over `lazy` option. Also supports execution modes for backward compatibility. |
353
+ | `engine` | `string` | `"singleton"` | **New** execution environment mode - `"singleton"`, `"vm"`, `"worker"`, or `"fork"` |
338
354
  | `apiDepth` | `number` | `Infinity` | Directory traversal depth control - `0` for root only, `Infinity` for all levels |
339
355
  | `debug` | `boolean` | `false` | Enable verbose logging. Can also be set via `--slothletdebug` command line flag or `SLOTHLET_DEBUG=true` environment variable |
340
- | `mode` | `string` | `"singleton"` | Execution environment mode - `"singleton"`, `"vm"`, `"worker"`, or `"fork"` |
341
356
  | `api_mode` | `string` | `"auto"` | API structure behavior when root-level default functions exist:<br/>• `"auto"`: Automatically detects if root has default function export and creates callable API<br/>• `"function"`: Forces API to be callable (use when you have root-level default function exports)<br/>• `"object"`: Forces API to be object-only (use when you want object interface regardless of exports) |
342
357
  | `context` | `object` | `{}` | Context data object injected into live-binding `context` reference. Available to all loaded modules via `import { context } from "@cldmv/slothlet/runtime"` |
343
358
  | `reference` | `object` | `{}` | Reference object merged into the API root level. Properties not conflicting with loaded modules are added directly to the API |
344
359
  | `sanitize` | `object` | `{}` | **🔧 NEW**: Control how filenames become API property names. Supports exact matches, glob patterns (`*json*`), and boundary patterns (`**url**`). Configure `lowerFirst` and `rules` for `leave`, `leaveInsensitive`, `upper`, and `lower` transformations |
345
360
 
361
+ #### ✨ New Option Format (v2.6.0+)
362
+
363
+ The option structure has been improved for better clarity:
364
+
365
+ ```javascript
366
+ // ✅ New recommended syntax
367
+ const api = await slothlet({
368
+ mode: "lazy", // Loading strategy: "lazy" | "eager"
369
+ engine: "singleton", // Execution environment: "singleton" | "vm" | "worker" | "fork"
370
+ dir: "./api"
371
+ });
372
+
373
+ // ✅ Legacy syntax (still fully supported)
374
+ const api = await slothlet({
375
+ lazy: true, // Boolean loading strategy
376
+ mode: "singleton", // Execution environment (legacy placement)
377
+ dir: "./api"
378
+ });
379
+
380
+ // ✅ Mixed usage (mode takes precedence)
381
+ const api = await slothlet({
382
+ lazy: false, // Will be overridden
383
+ mode: "lazy", // Takes precedence - results in lazy loading
384
+ engine: "singleton"
385
+ });
386
+ ```
387
+
388
+ **Benefits of the new syntax:**
389
+
390
+ - **Clearer separation**: `mode` for loading strategy, `engine` for execution environment
391
+ - **Better discoverability**: String values are more self-documenting than boolean flags
392
+ - **Future-proof**: Easier to extend with additional loading strategies
393
+ - **Backward compatible**: All existing code continues to work unchanged
394
+
346
395
  #### `slothlet.getApi()` ⇒ `object`
347
396
 
348
397
  Returns the raw API object (Proxy or plain object).
@@ -1157,6 +1206,11 @@ Key highlights:
1157
1206
  - **[Security Policy](https://github.com/CLDMV/slothlet/blob/HEAD/SECURITY.md)** - Security guidelines and reporting
1158
1207
  - **[Test Documentation](https://github.com/CLDMV/slothlet/blob/HEAD/api_tests)** - Comprehensive test module examples
1159
1208
 
1209
+ ### 🔧 Technical Documentation
1210
+
1211
+ - **[API Rules](https://github.com/CLDMV/slothlet/blob/HEAD/API-RULES.md)** - Systematically verified API transformation rules with real examples and test cases
1212
+ - **[API Rules Conditions](https://github.com/CLDMV/slothlet/blob/HEAD/API-RULES-CONDITIONS.md)** - Complete technical reference of all 26 conditional statements that control API generation
1213
+
1160
1214
  ---
1161
1215
 
1162
1216
  ## 🔗 Links
@@ -20,10 +20,13 @@
20
20
 
21
21
  import { AsyncResource } from "node:async_hooks";
22
22
  import { EventEmitter } from "node:events";
23
- import { sharedALS } from "../runtime/runtime.mjs";
23
+ import { AsyncLocalStorage } from "node:async_hooks";
24
24
 
25
25
 
26
- export function enableAlsForEventEmitters(als = sharedALS) {
26
+ const defaultALS = new AsyncLocalStorage();
27
+
28
+
29
+ export function enableAlsForEventEmitters(als = defaultALS) {
27
30
 
28
31
  const kPatched = Symbol.for("slothlet.als.patched");
29
32
 
@@ -115,5 +118,3 @@ export function enableAlsForEventEmitters(als = sharedALS) {
115
118
  return res;
116
119
  };
117
120
  }
118
-
119
-
@@ -22,6 +22,8 @@ import fs from "node:fs/promises";
22
22
  import path from "node:path";
23
23
  import { types as utilTypes } from "node:util";
24
24
  import { pathToFileURL } from "node:url";
25
+ import { multidefault_analyzeModules } from "@cldmv/slothlet/helpers/multidefault";
26
+ import { setActiveInstance } from "@cldmv/slothlet/helpers/instance-manager";
25
27
 
26
28
 
27
29
 
@@ -48,10 +50,29 @@ function isLikelySerializable(val) {
48
50
 
49
51
 
50
52
  export async function analyzeModule(modulePath, options = {}) {
51
- const { debug = false } = options;
53
+ const { debug = false, instance = null } = options;
52
54
 
53
55
  const moduleUrl = pathToFileURL(modulePath).href;
54
- const rawModule = await import(moduleUrl);
56
+
57
+
58
+ let importUrl = moduleUrl;
59
+ if (instance && instance.instanceId) {
60
+ const runtimeType = instance.config?.runtime || "async";
61
+
62
+
63
+ if (runtimeType === "live") {
64
+ const separator = moduleUrl.includes("?") ? "&" : "?";
65
+ importUrl = `${moduleUrl}${separator}slothlet_instance=${instance.instanceId}`;
66
+ importUrl = `${importUrl}&slothlet_runtime=${runtimeType}`;
67
+
68
+
69
+ setActiveInstance(instance.instanceId);
70
+ }
71
+
72
+
73
+ }
74
+
75
+ const rawModule = await import(importUrl);
55
76
 
56
77
 
57
78
  let processedModule = rawModule;
@@ -361,8 +382,7 @@ export async function analyzeDirectoryStructure(categoryPath, options = {}) {
361
382
 
362
383
  let multiDefaultAnalysis = null;
363
384
  if (processingStrategy === "multi-file") {
364
- const { multidefault_analyzeModules } = await import("@cldmv/slothlet/helpers/multidefault");
365
- multiDefaultAnalysis = await multidefault_analyzeModules(moduleFiles, categoryPath, debug);
385
+ multiDefaultAnalysis = await multidefault_analyzeModules(moduleFiles, categoryPath, { debug, instance });
366
386
  }
367
387
 
368
388
 
@@ -949,8 +969,7 @@ export async function buildCategoryStructure(categoryPath, options = {}) {
949
969
  const categoryModules = {};
950
970
 
951
971
 
952
- const { multidefault_analyzeModules } = await import("@cldmv/slothlet/helpers/multidefault");
953
- const analysis = await multidefault_analyzeModules(moduleFiles, categoryPath, debug);
972
+ const analysis = await multidefault_analyzeModules(moduleFiles, categoryPath, { debug, instance });
954
973
  const { totalDefaultExports, hasMultipleDefaultExports, selfReferentialFiles, defaultExportFiles: analysisDefaults } = analysis;
955
974
 
956
975
 
@@ -1090,8 +1109,7 @@ export async function buildRootAPI(dir, options = {}) {
1090
1109
 
1091
1110
  if (moduleFiles.length > 0) {
1092
1111
 
1093
- const { multidefault_analyzeModules } = await import("@cldmv/slothlet/helpers/multidefault");
1094
- const analysis = await multidefault_analyzeModules(moduleFiles, dir, debug);
1112
+ const analysis = await multidefault_analyzeModules(moduleFiles, dir, { debug, instance });
1095
1113
  const { hasMultipleDefaultExports, selfReferentialFiles } = analysis;
1096
1114
 
1097
1115
 
@@ -1193,9 +1211,6 @@ export async function buildCategoryDecisions(categoryPath, options = {}) {
1193
1211
  console.log(`[DEBUG] buildCategoryDecisions called with path: ${categoryPath}, mode: ${mode}`);
1194
1212
  }
1195
1213
 
1196
- const fs = await import("fs/promises");
1197
- const path = await import("path");
1198
-
1199
1214
  const files = await fs.readdir(categoryPath, { withFileTypes: true });
1200
1215
  const moduleFiles = files.filter((f) => instance._shouldIncludeFile(f));
1201
1216
  const categoryName = instance._toapiPathKey(path.basename(categoryPath));
@@ -1390,8 +1405,7 @@ export async function buildCategoryDecisions(categoryPath, options = {}) {
1390
1405
  }
1391
1406
 
1392
1407
 
1393
- const { multidefault_analyzeModules } = await import("@cldmv/slothlet/helpers/multidefault");
1394
- const analysis = await multidefault_analyzeModules(moduleFiles, categoryPath, debug);
1408
+ const analysis = await multidefault_analyzeModules(moduleFiles, categoryPath, { debug, instance });
1395
1409
 
1396
1410
  decisions.multifileAnalysis = analysis;
1397
1411
 
@@ -22,13 +22,15 @@
22
22
  export async function autoWrapEventEmitters(nodeModule) {
23
23
 
24
24
  try {
25
- const { self } = await import("@cldmv/slothlet/runtime");
25
+
26
+
27
+ const { self } = await import("@cldmv/slothlet/runtime/async");
26
28
  if (!self?.__ctx) {
27
29
 
28
30
  return nodeModule;
29
31
  }
30
32
 
31
- const { makeWrapper } = await import("../runtime/runtime.mjs");
33
+ const { makeWrapper } = await import("@cldmv/slothlet/runtime/async");
32
34
  const wrapper = makeWrapper(self.__ctx);
33
35
 
34
36
 
@@ -0,0 +1,111 @@
1
+ /*
2
+ Copyright 2025 CLDMV/Shinrai
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ */
16
+
17
+ 
18
+
19
+
20
+ const instanceRegistry = new Map();
21
+
22
+
23
+ let currentActiveInstanceId = null;
24
+
25
+
26
+ export function getInstanceData(instanceId) {
27
+ return instanceRegistry.get(instanceId) || null;
28
+ }
29
+
30
+
31
+ export function updateInstanceData(instanceId, key, value) {
32
+
33
+
34
+
35
+
36
+
37
+
38
+ let instanceData = instanceRegistry.get(instanceId);
39
+ if (!instanceData) {
40
+ instanceData = {
41
+ self: null,
42
+ context: {},
43
+ reference: {}
44
+ };
45
+ instanceRegistry.set(instanceId, instanceData);
46
+ }
47
+ instanceData[key] = value;
48
+
49
+
50
+ }
51
+
52
+
53
+ export async function cleanupInstance(instanceId) {
54
+
55
+ instanceRegistry.delete(instanceId);
56
+
57
+ if (currentActiveInstanceId === instanceId) {
58
+ currentActiveInstanceId = null;
59
+ }
60
+ }
61
+
62
+
63
+ export function setActiveInstance(instanceId) {
64
+ currentActiveInstanceId = instanceId;
65
+
66
+ }
67
+
68
+
69
+ export function getCurrentActiveInstanceId() {
70
+ return currentActiveInstanceId;
71
+ }
72
+
73
+
74
+ export function detectCurrentInstanceId() {
75
+
76
+
77
+
78
+
79
+
80
+
81
+
82
+
83
+ if (currentActiveInstanceId && instanceRegistry.has(currentActiveInstanceId)) {
84
+ return currentActiveInstanceId;
85
+ }
86
+
87
+
88
+ const stack = new Error().stack;
89
+ if (stack) {
90
+
91
+ const matches = stack.match(/slothlet_instance=([^&\s):]+)/g);
92
+
93
+ if (matches && matches.length > 0) {
94
+
95
+ const instanceParam = matches[0];
96
+ const instanceId = instanceParam.replace(/slothlet_instance=([^&\s):]+).*/, "$1");
97
+
98
+ if (instanceRegistry.has(instanceId)) {
99
+ return instanceId;
100
+ }
101
+ }
102
+ }
103
+
104
+
105
+ return null;
106
+ }
107
+
108
+
109
+ export function getAllInstanceIds() {
110
+ return Array.from(instanceRegistry.keys());
111
+ }
@@ -16,10 +16,13 @@
16
16
 
17
17
 
18
18
 
19
+
20
+
19
21
  import path from "path";
20
22
 
21
23
 
22
- async function multidefault_analyzeModules(moduleFiles, baseDir, debug = false) {
24
+ async function multidefault_analyzeModules(moduleFiles, baseDir, options = {}) {
25
+ const { debug = false, instance = null } = options;
23
26
  const selfReferentialFiles = new Set();
24
27
  const rawModuleCache = new Map();
25
28
  const defaultExportFiles = [];
@@ -36,7 +39,14 @@ async function multidefault_analyzeModules(moduleFiles, baseDir, debug = false)
36
39
  const moduleFilePath = path.resolve(baseDir, file.name);
37
40
 
38
41
 
39
- const rawImport = await import(`file://${moduleFilePath.replace(/\\/g, "/")}`);
42
+ let importUrl = `file://${moduleFilePath.replace(/\\/g, "/")}`;
43
+ if (instance && instance.instanceId) {
44
+ const separator = importUrl.includes("?") ? "&" : "?";
45
+ importUrl = `${importUrl}${separator}slothlet_instance=${instance.instanceId}`;
46
+ }
47
+
48
+
49
+ const rawImport = await import(importUrl);
40
50
 
41
51
 
42
52
  const isCjsFile = moduleExt === ".cjs";
@@ -38,7 +38,7 @@ export async function create(dir, maxDepth = Infinity, currentDepth = 0) {
38
38
  const moduleFiles = entries.filter((e) => this._shouldIncludeFile(e));
39
39
  const defaultExportFiles = [];
40
40
 
41
- const analysis = await multidefault_analyzeModules(moduleFiles, dir, this.config.debug);
41
+ const analysis = await multidefault_analyzeModules(moduleFiles, dir, { debug: this.config.debug, instance: this });
42
42
 
43
43
  const { totalDefaultExports, hasMultipleDefaultExports, selfReferentialFiles, defaultExportFiles: analysisDefaults } = analysis;
44
44
 
@@ -21,13 +21,17 @@ import fs from "node:fs/promises";
21
21
  import { readdirSync } from "node:fs";
22
22
  import path from "node:path";
23
23
  import { types as utilTypes } from "node:util";
24
- import { runWithCtx } from "@cldmv/slothlet/runtime";
25
24
  import { processModuleForAPI } from "@cldmv/slothlet/helpers/api_builder";
26
25
  import { multidefault_analyzeModules } from "@cldmv/slothlet/helpers/multidefault";
27
26
 
28
27
 
29
28
  export async function create(dir, maxDepth = Infinity, currentDepth = 0) {
30
29
  const instance = this;
30
+
31
+
32
+ const runtimePath = instance.config.runtime === "live" ? "@cldmv/slothlet/runtime/live" : "@cldmv/slothlet/runtime/async";
33
+ const { runWithCtx } = await import(runtimePath);
34
+
31
35
  const entries = await fs.readdir(dir, { withFileTypes: true });
32
36
  let api = {};
33
37
  let rootDefaultFn = null;
@@ -38,7 +42,7 @@ export async function create(dir, maxDepth = Infinity, currentDepth = 0) {
38
42
  const defaultExportFiles = [];
39
43
 
40
44
 
41
- const analysis = await multidefault_analyzeModules(moduleFiles, dir, instance.config.debug);
45
+ const analysis = await multidefault_analyzeModules(moduleFiles, dir, { debug: instance.config.debug, instance });
42
46
 
43
47
  const { totalDefaultExports, hasMultipleDefaultExports, selfReferentialFiles, defaultExportFiles: analysisDefaults } = analysis;
44
48
 
@@ -156,7 +160,8 @@ export async function create(dir, maxDepth = Infinity, currentDepth = 0) {
156
160
  instance,
157
161
  depth,
158
162
  maxDepth,
159
- pathParts: [key]
163
+ pathParts: [key],
164
+ runWithCtx
160
165
  });
161
166
  parent[key] = proxy;
162
167
  }
@@ -223,7 +228,7 @@ function replacePlaceholder(parent, key, placeholder, value, instance, depth) {
223
228
  }
224
229
 
225
230
 
226
- function createFolderProxy({ subDirPath, key, parent, instance, depth, maxDepth, pathParts }) {
231
+ function createFolderProxy({ subDirPath, key, parent, instance, depth, maxDepth, pathParts, runWithCtx }) {
227
232
  let materialized = null;
228
233
  let inFlight = null;
229
234
 
@@ -246,7 +251,8 @@ function createFolderProxy({ subDirPath, key, parent, instance, depth, maxDepth,
246
251
  instance,
247
252
  depth: cd + 1,
248
253
  maxDepth: md,
249
- pathParts: [...pathParts, nestedKey]
254
+ pathParts: [...pathParts, nestedKey],
255
+ runWithCtx
250
256
  })
251
257
  });
252
258
  materialized = value;
@@ -374,6 +380,43 @@ function createFolderProxy({ subDirPath, key, parent, instance, depth, maxDepth,
374
380
  return new Proxy(
375
381
  function lazy_deepPropertyAccessor() {},
376
382
  {
383
+ get(target, nextProp) {
384
+ if (nextProp === "name") return `lazy_${prop}_${subProp}`;
385
+ if (nextProp === "length") return 0;
386
+
387
+ return new Proxy(function lazy_deeperPropertyAccessor() {}, {
388
+ apply(target, thisArg, args) {
389
+ if (materialized) {
390
+ const value = materialized[prop];
391
+ const subValue = value ? value[subProp] : undefined;
392
+ if (subValue && typeof subValue[nextProp] === "function") {
393
+ const ctx = instance.boundapi?.__ctx;
394
+ if (ctx) {
395
+ return runWithCtx(ctx, subValue[nextProp], thisArg, args);
396
+ } else {
397
+ return subValue[nextProp].apply(thisArg, args);
398
+ }
399
+ }
400
+ return subValue ? subValue[nextProp] : undefined;
401
+ }
402
+
403
+ if (!inFlight) inFlight = _materialize();
404
+ return inFlight.then(function lazy_handleDeeperResolvedValue(resolved) {
405
+ const value = resolved ? resolved[prop] : undefined;
406
+ const subValue = value ? value[subProp] : undefined;
407
+ if (subValue && typeof subValue[nextProp] === "function") {
408
+ const ctx = instance.boundapi?.__ctx;
409
+ if (ctx) {
410
+ return runWithCtx(ctx, subValue[nextProp], thisArg, args);
411
+ } else {
412
+ return subValue[nextProp].apply(thisArg, args);
413
+ }
414
+ }
415
+ return subValue ? subValue[nextProp] : undefined;
416
+ });
417
+ }
418
+ });
419
+ },
377
420
  apply(target, thisArg, args) {
378
421
 
379
422
  if (materialized) {