@cldmv/slothlet 2.3.0 → 2.3.2

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 (36) hide show
  1. package/README.md +146 -3
  2. package/dist/lib/engine/slothlet_child.mjs +1 -0
  3. package/dist/lib/engine/slothlet_engine.mjs +1 -0
  4. package/dist/lib/engine/slothlet_esm.mjs +1 -0
  5. package/dist/lib/engine/slothlet_helpers.mjs +2 -1
  6. package/dist/lib/engine/slothlet_worker.mjs +1 -0
  7. package/dist/lib/helpers/als-eventemitter.mjs +119 -0
  8. package/dist/lib/helpers/auto-wrap.mjs +60 -0
  9. package/dist/lib/helpers/resolve-from-caller.mjs +1 -0
  10. package/dist/lib/helpers/sanitize.mjs +2 -0
  11. package/dist/lib/modes/slothlet_eager.mjs +4 -2
  12. package/dist/lib/modes/slothlet_lazy.mjs +4 -2
  13. package/dist/lib/runtime/runtime.mjs +73 -3
  14. package/dist/slothlet.mjs +7 -20
  15. package/index.cjs +4 -4
  16. package/index.mjs +2 -2
  17. package/package.json +2 -1
  18. package/types/dist/lib/engine/slothlet_engine.d.mts +1 -1
  19. package/types/dist/lib/engine/slothlet_engine.d.mts.map +1 -1
  20. package/types/dist/lib/engine/slothlet_esm.d.mts.map +1 -1
  21. package/types/dist/lib/engine/slothlet_helpers.d.mts +2 -1
  22. package/types/dist/lib/engine/slothlet_helpers.d.mts.map +1 -1
  23. package/types/dist/lib/helpers/als-eventemitter.d.mts +23 -0
  24. package/types/dist/lib/helpers/als-eventemitter.d.mts.map +1 -0
  25. package/types/dist/lib/helpers/auto-wrap.d.mts +49 -0
  26. package/types/dist/lib/helpers/auto-wrap.d.mts.map +1 -0
  27. package/types/dist/lib/helpers/resolve-from-caller.d.mts +14 -14
  28. package/types/dist/lib/helpers/resolve-from-caller.d.mts.map +1 -1
  29. package/types/dist/lib/helpers/sanitize.d.mts.map +1 -1
  30. package/types/dist/lib/modes/slothlet_eager.d.mts.map +1 -1
  31. package/types/dist/lib/modes/slothlet_lazy.d.mts.map +1 -1
  32. package/types/dist/lib/runtime/runtime.d.mts +9 -0
  33. package/types/dist/lib/runtime/runtime.d.mts.map +1 -1
  34. package/types/dist/slothlet.d.mts +1 -8
  35. package/types/dist/slothlet.d.mts.map +1 -1
  36. package/types/index.d.mts +0 -1
package/README.md CHANGED
@@ -33,9 +33,9 @@ The name might suggest we're taking it easy, but don't be fooled. **Slothlet del
33
33
 
34
34
  ---
35
35
 
36
- ## ✨ What's New in v2.0
36
+ ## ✨ What's New in v2.x
37
37
 
38
- ### 🎯 **Complete Architectural Rewrite**
38
+ ### 🎯 **Complete Architectural Rewrite (v2.0)**
39
39
 
40
40
  v2.0 represents a ground-up rewrite with enterprise-grade features:
41
41
 
@@ -67,6 +67,13 @@ v2.0 represents a ground-up rewrite with enterprise-grade features:
67
67
  - **Memory**: On-demand loading scales with actual usage
68
68
  - **Predictability**: Consistent performance characteristics per mode
69
69
 
70
+ ### 🔄 **Context Propagation (v2.3)** ⭐ NEW
71
+
72
+ - **EventEmitter Context Propagation**: Automatic context preservation across EventEmitter callbacks using AsyncResource patterns
73
+ - **Class Instance Context Propagation**: Automatic context preservation across class method calls with transparent wrapping
74
+ - **AsyncResource Integration**: Production-ready context management following Node.js best practices
75
+ - **Zero Configuration**: Works automatically with TCP servers, HTTP servers, and any EventEmitter-based patterns
76
+
70
77
  ---
71
78
 
72
79
  ## 🚀 Key Features
@@ -332,7 +339,7 @@ Creates and loads an API instance with the specified configuration.
332
339
  | `debug` | `boolean` | `false` | Enable verbose logging. Can also be set via `--slothletdebug` command line flag or `SLOTHLET_DEBUG=true` environment variable |
333
340
  | `mode` | `string` | `"singleton"` | Execution environment mode - `"singleton"`, `"vm"`, `"worker"`, or `"fork"` |
334
341
  | `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) |
335
- | `context` | `object` | `{}` | Context data object injected into live-binding `context` reference. Available to all loaded modules via `import { context } from '@cldmv/slothlet/runtime'` |
342
+ | `context` | `object` | `{}` | Context data object injected into live-binding `context` reference. Available to all loaded modules via `import { context } from "@cldmv/slothlet/runtime"` |
336
343
  | `reference` | `object` | `{}` | Reference object merged into the API root level. Properties not conflicting with loaded modules are added directly to the API |
337
344
  | `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 |
338
345
 
@@ -419,6 +426,142 @@ function cjsFunction(data) {
419
426
  module.exports = { cjsFunction };
420
427
  ```
421
428
 
429
+ ### EventEmitter Context Propagation
430
+
431
+ Slothlet automatically preserves AsyncLocalStorage context across all EventEmitter callbacks using Node.js AsyncResource patterns. This ensures your API modules maintain full context access in event handlers without any configuration.
432
+
433
+ ```javascript
434
+ // api/tcp-server.mjs - Your API module
435
+ import { self, context } from "@cldmv/slothlet/runtime";
436
+ import net from "node:net";
437
+
438
+ export function createTcpServer() {
439
+ const server = net.createServer();
440
+
441
+ // Connection handler maintains full context automatically
442
+ server.on("connection", (socket) => {
443
+ console.log(`User: ${context.user}`); // ✅ Context preserved
444
+ console.log(`API keys: ${Object.keys(self).length}`); // ✅ Full API access
445
+
446
+ // Socket data handler also maintains context automatically
447
+ socket.on("data", (data) => {
448
+ console.log(`Session: ${context.session}`); // ✅ Context preserved
449
+ console.log(`Processing for: ${context.user}`); // ✅ Context preserved
450
+
451
+ // Full API access in nested event handlers
452
+ const processed = self.dataProcessor.handle(data.toString());
453
+ socket.write(processed);
454
+ });
455
+
456
+ socket.on("error", (err) => {
457
+ // Error handlers also maintain context
458
+ self.logger.error(`Error for user ${context.user}: ${err.message}`);
459
+ });
460
+ });
461
+
462
+ return server;
463
+ }
464
+
465
+ export function startServer(port = 3000) {
466
+ const server = createTcpServer();
467
+ server.listen(port);
468
+ return server;
469
+ }
470
+ ```
471
+
472
+ ```javascript
473
+ // Usage in your application
474
+ import slothlet from "@cldmv/slothlet";
475
+
476
+ const api = await slothlet({
477
+ dir: "./api",
478
+ context: { user: "alice", session: "tcp-session" }
479
+ });
480
+
481
+ // Start the server - all event handlers will have full context
482
+ const server = api.startServer(8080);
483
+ console.log("TCP server started with context preservation");
484
+ ```
485
+
486
+ **Key Benefits:**
487
+
488
+ - ✅ **Automatic**: No configuration needed - works transparently in all API modules
489
+ - ✅ **Complete Context**: Full `context` object and `self` API access in all event handlers
490
+ - ✅ **Nested Events**: Works with any depth of EventEmitter nesting (server → socket → custom emitters)
491
+ - ✅ **Universal Support**: All EventEmitter methods (`on`, `once`, `addListener`) are automatically context-aware
492
+ - ✅ **Production Ready**: Uses Node.js AsyncResource patterns for reliable context propagation
493
+ - ✅ **Zero Overhead**: Only wraps listeners when context is active, minimal performance impact
494
+
495
+ > [!TIP]
496
+ > **Automatic Context Propagation**: EventEmitter context propagation works automatically in both lazy and eager modes. TCP servers, HTTP servers, custom EventEmitters, and any other event-driven patterns in your API modules will maintain full slothlet context and API access without any code changes.
497
+
498
+ ### Class Instance Context Propagation
499
+
500
+ Slothlet automatically preserves AsyncLocalStorage context across all class instance method calls. When your API functions return class instances, slothlet wraps them transparently to ensure all method calls maintain full context access.
501
+
502
+ ```javascript
503
+ // api/data-processor.mjs - Your API module
504
+ import { self, context } from "@cldmv/slothlet/runtime";
505
+
506
+ class DataProcessor {
507
+ constructor(config) {
508
+ this.config = config;
509
+ }
510
+
511
+ process(data) {
512
+ // Context automatically available in all methods
513
+ console.log(`Processing for user: ${context.user}`); // ✅ Context preserved
514
+ console.log(`Request ID: ${context.requestId}`); // ✅ Context preserved
515
+
516
+ // Full API access in class methods
517
+ const validated = self.validator.check(data);
518
+ return this.transform(validated);
519
+ }
520
+
521
+ transform(data) {
522
+ // Context preserved in nested method calls
523
+ console.log(`Transforming for: ${context.user}`); // ✅ Context preserved
524
+
525
+ // Call other API modules from class methods
526
+ return self.utils.format(data);
527
+ }
528
+ }
529
+
530
+ export function createProcessor(config) {
531
+ // Return class instance - slothlet automatically wraps it
532
+ return new DataProcessor(config);
533
+ }
534
+ ```
535
+
536
+ ```javascript
537
+ // Usage in your application
538
+ import slothlet from "@cldmv/slothlet";
539
+
540
+ const api = await slothlet({
541
+ dir: "./api",
542
+ context: { user: "alice", requestId: "req-123" }
543
+ });
544
+
545
+ // Create processor instance - all methods will have full context
546
+ const processor = api.createProcessor({ format: "json" });
547
+
548
+ // All method calls maintain context automatically
549
+ const result = processor.process({ data: "test" });
550
+ console.log("Processing completed with context preservation");
551
+ ```
552
+
553
+ **Key Benefits:**
554
+
555
+ - ✅ **Automatic**: Class instances returned from API functions are automatically context-aware
556
+ - ✅ **Transparent**: No code changes needed - works with existing class patterns
557
+ - ✅ **Complete Context**: Full `context` object and `self` API access in all class methods
558
+ - ✅ **Nested Methods**: Context preserved across method chains and internal calls
559
+ - ✅ **Constructor Support**: Context preserved for both function calls and `new` constructor usage
560
+ - ✅ **Performance Optimized**: Method wrapping is cached to avoid overhead on repeated calls
561
+
562
+ > [!TIP]
563
+ > **Universal Class Support**: Any class instance returned from your API functions automatically maintains slothlet context. This includes database models, service classes, utility classes, and any other object-oriented patterns in your codebase.
564
+
422
565
  ### API Mode Configuration
423
566
 
424
567
  The `api_mode` option controls how slothlet handles root-level default function exports:
@@ -15,6 +15,7 @@
15
15
  */
16
16
 
17
17
 
18
+
18
19
  import { installGlobalsInCurrentRealm, extendSelfWithReference, installPortalForSelf } from "./slothlet_helpers.mjs";
19
20
 
20
21
  let initialized = false;
@@ -15,6 +15,7 @@
15
15
  */
16
16
 
17
17
 
18
+
18
19
  import { Worker } from "node:worker_threads";
19
20
  import { fork } from "node:child_process";
20
21
  import { fileURLToPath } from "node:url";
@@ -15,6 +15,7 @@
15
15
  */
16
16
 
17
17
 
18
+
18
19
  import fs from "node:fs/promises";
19
20
  import path from "node:path";
20
21
  import { fileURLToPath } from "node:url";
@@ -15,6 +15,7 @@
15
15
  */
16
16
 
17
17
 
18
+
18
19
  import vm from "node:vm";
19
20
  import fs from "node:fs/promises";
20
21
  import path from "node:path";
@@ -389,7 +390,7 @@ export async function bootSlothletVM(context, entryUrl, loadConfig, ctxRef) {
389
390
  const ret = await globalThis.slothlet.load(__loadConfig, __ctxRef);
390
391
  globalThis.self = global.self = ret;
391
392
  const ref = __ctxRef?.reference;
392
- if (ref && typeof ref === 'object') {
393
+ if (ref && typeof ref === "object") {
393
394
  for (const k of Object.keys(ref)) if (!(k in globalThis.self)) {
394
395
  try { globalThis.self[k] = global.self[k] = ref[k]; } catch {}
395
396
  }
@@ -15,6 +15,7 @@
15
15
  */
16
16
 
17
17
 
18
+
18
19
  import { parentPort, workerData } from "node:worker_threads";
19
20
  import {
20
21
  installGlobalsInCurrentRealm,
@@ -0,0 +1,119 @@
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
+
21
+ import { AsyncResource } from "node:async_hooks";
22
+ import { EventEmitter } from "node:events";
23
+ import { sharedALS } from "../runtime/runtime.mjs";
24
+
25
+
26
+ export function enableAlsForEventEmitters(als = sharedALS) {
27
+
28
+ const kPatched = Symbol.for("slothlet.als.patched");
29
+
30
+ if (EventEmitter.prototype[kPatched]) return;
31
+ EventEmitter.prototype[kPatched] = true;
32
+
33
+
34
+ const kMap = Symbol("slothlet.als.listenerMap");
35
+
36
+
37
+ function runtime_ensureMap(emitter) {
38
+ if (!emitter[kMap]) emitter[kMap] = new WeakMap();
39
+ return emitter[kMap];
40
+ }
41
+
42
+
43
+ function runtime_wrapListener(listener) {
44
+
45
+ const store = als.getStore();
46
+ if (!store) return listener;
47
+
48
+
49
+ const resource = new AsyncResource("slothlet-als-listener");
50
+
51
+
52
+ const runtime_wrappedListener = function (...args) {
53
+ return resource.runInAsyncScope(
54
+ () => {
55
+ return listener.apply(this, args);
56
+ },
57
+ this,
58
+ ...args
59
+ );
60
+ };
61
+
62
+ return runtime_wrappedListener;
63
+ }
64
+
65
+ const proto = EventEmitter.prototype;
66
+
67
+
68
+ const origOn = proto.on;
69
+ const origOnce = proto.once;
70
+ const origAdd = proto.addListener;
71
+ const origPre = proto.prependListener;
72
+ const origPreO = proto.prependOnceListener;
73
+ const origOff = proto.off ?? proto.removeListener;
74
+ const origRem = proto.removeListener;
75
+
76
+
77
+ function runtime_installWrapper(addFnName, orig) {
78
+ proto[addFnName] = function (event, listener) {
79
+ const map = runtime_ensureMap(this);
80
+ const wrapped = runtime_wrapListener(listener);
81
+ if (wrapped !== listener) map.set(listener, wrapped);
82
+ return orig.call(this, event, wrapped);
83
+ };
84
+ }
85
+
86
+
87
+ runtime_installWrapper("on", origOn);
88
+ runtime_installWrapper("once", origOnce);
89
+ runtime_installWrapper("addListener", origAdd);
90
+ if (origPre) runtime_installWrapper("prependListener", origPre);
91
+ if (origPreO) runtime_installWrapper("prependOnceListener", origPreO);
92
+
93
+
94
+ function runtime_createRemoveWrapper(method) {
95
+
96
+ const runtime_removeWrapper = function (event, listener) {
97
+ const map = runtime_ensureMap(this);
98
+ const wrapped = map.get(listener) || listener;
99
+ map.delete(listener);
100
+ return method.call(this, event, wrapped);
101
+ };
102
+
103
+ return runtime_removeWrapper;
104
+ }
105
+
106
+
107
+ if (proto.off) proto.off = runtime_createRemoveWrapper(origOff);
108
+ proto.removeListener = runtime_createRemoveWrapper(origRem);
109
+
110
+
111
+ const origRemoveAll = proto.removeAllListeners;
112
+ proto.removeAllListeners = function (event) {
113
+ const res = origRemoveAll.call(this, event);
114
+ if (this[kMap]) this[kMap] = new WeakMap();
115
+ return res;
116
+ };
117
+ }
118
+
119
+
@@ -0,0 +1,60 @@
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
+
21
+
22
+ export async function autoWrapEventEmitters(nodeModule) {
23
+
24
+ try {
25
+ const { self } = await import("@cldmv/slothlet/runtime");
26
+ if (!self?.__ctx) {
27
+
28
+ return nodeModule;
29
+ }
30
+
31
+ const { makeWrapper } = await import("../runtime/runtime.mjs");
32
+ const wrapper = makeWrapper(self.__ctx);
33
+
34
+
35
+ const wrappedModule = { ...nodeModule };
36
+
37
+
38
+ if (typeof nodeModule.createServer === "function") {
39
+ const originalCreateServer = nodeModule.createServer;
40
+ wrappedModule.createServer = function (...args) {
41
+ const server = originalCreateServer.apply(this, args);
42
+ return wrapper(server);
43
+ };
44
+ }
45
+
46
+ return wrappedModule;
47
+ } catch (err) {
48
+
49
+ console.error("autoWrapEventEmitters error:", err);
50
+ return nodeModule;
51
+ }
52
+ }
53
+
54
+
55
+ export async function getNet() {
56
+ const originalNet = await import("node:net");
57
+ return autoWrapEventEmitters(originalNet.default || originalNet);
58
+ }
59
+
60
+
@@ -17,6 +17,7 @@
17
17
 
18
18
 
19
19
 
20
+
20
21
  import fs from "node:fs";
21
22
  import path from "node:path";
22
23
  import { fileURLToPath, pathToFileURL } from "node:url";
@@ -17,6 +17,8 @@
17
17
 
18
18
 
19
19
 
20
+
21
+
20
22
  function globToRegex(pattern, caseSensitive = true) {
21
23
  try {
22
24
 
@@ -18,8 +18,10 @@
18
18
 
19
19
 
20
20
 
21
- import fs from "fs/promises";
22
- import path from "path";
21
+
22
+
23
+ import fs from "node:fs/promises";
24
+ import path from "node:path";
23
25
 
24
26
 
25
27
 
@@ -15,8 +15,10 @@
15
15
  */
16
16
 
17
17
 
18
- import fs from "fs/promises";
19
- import path from "path";
18
+
19
+
20
+ import fs from "node:fs/promises";
21
+ import path from "node:path";
20
22
  import { runWithCtx } from "@cldmv/slothlet/runtime";
21
23
 
22
24
 
@@ -16,12 +16,21 @@
16
16
 
17
17
 
18
18
 
19
+
20
+
19
21
  import { AsyncLocalStorage } from "node:async_hooks";
20
22
  import util from "node:util";
23
+ import { enableAlsForEventEmitters } from "@cldmv/slothlet/helpers/als-eventemitter";
21
24
 
22
25
  const als = new AsyncLocalStorage();
23
26
 
24
27
 
28
+ export const sharedALS = new AsyncLocalStorage();
29
+
30
+
31
+ enableAlsForEventEmitters(als);
32
+
33
+
25
34
  export const runWithCtx = (ctx, fn, thisArg, args) => {
26
35
 
27
36
  const runtime_runInALS = () => {
@@ -41,6 +50,9 @@ const EXCLUDED_CONSTRUCTORS = new Set([Object, Array, Promise, Date, RegExp, Err
41
50
  const EXCLUDED_INSTANCEOF_CLASSES = [ArrayBuffer, Map, Set, WeakMap, WeakSet];
42
51
 
43
52
 
53
+ const PROMISE_METHODS = new Set(["then", "catch", "finally"]);
54
+
55
+
44
56
  function runtime_shouldWrapMethod(value, prop) {
45
57
  return (
46
58
  typeof value === "function" &&
@@ -127,6 +139,7 @@ function runtime_wrapClassInstance(instance, ctx, wrapFn, instanceCache) {
127
139
  export const makeWrapper = (ctx) => {
128
140
  const cache = new WeakMap();
129
141
  const instanceCache = new WeakMap();
142
+ const promiseMethodCache = new WeakMap();
130
143
  const wrap = (val) => {
131
144
  if (val == null || (typeof val !== "object" && typeof val !== "function")) return val;
132
145
  if (cache.has(val)) return cache.get(val);
@@ -165,11 +178,66 @@ export const makeWrapper = (ctx) => {
165
178
  return result;
166
179
  },
167
180
  get(target, prop, receiver) {
168
- return wrap(Reflect.get(target, prop, receiver));
181
+ const value = Reflect.get(target, prop, receiver);
182
+
183
+
184
+
185
+ const isPromiseMethod = typeof value === "function" && PROMISE_METHODS.has(prop);
186
+ const isNativePromise = util.types.isPromise(target);
187
+ const hasThen = typeof target?.then === "function";
188
+
189
+ if (isPromiseMethod && (isNativePromise || hasThen)) {
190
+
191
+ let targetMethodCache = promiseMethodCache.get(target);
192
+ if (!targetMethodCache) {
193
+ targetMethodCache = new Map();
194
+ promiseMethodCache.set(target, targetMethodCache);
195
+ }
196
+
197
+ if (targetMethodCache.has(prop)) {
198
+ return targetMethodCache.get(prop);
199
+ }
200
+
201
+ const wrappedMethod = function (...args) {
202
+
203
+ const wrappedArgs = args.map((arg) => {
204
+ if (typeof arg === "function") {
205
+ return function (...callbackArgs) {
206
+ return runWithCtx(ctx, arg, undefined, callbackArgs);
207
+ };
208
+ }
209
+ return arg;
210
+ });
211
+
212
+
213
+ const result = Reflect.apply(value, target, wrappedArgs);
214
+
215
+ return wrap(result);
216
+ };
217
+
218
+ targetMethodCache.set(prop, wrappedMethod);
219
+ return wrappedMethod;
220
+ }
221
+
222
+ return wrap(value);
223
+ },
224
+ set(target, prop, value, receiver) {
225
+
226
+ const methodCache = promiseMethodCache.get(target);
227
+ if (methodCache && methodCache.has(prop)) {
228
+ methodCache.delete(prop);
229
+ }
230
+ return Reflect.set(target, prop, value, receiver);
169
231
  },
170
- set: Reflect.set,
171
232
  defineProperty: Reflect.defineProperty,
172
- deleteProperty: Reflect.deleteProperty,
233
+ deleteProperty(target, prop) {
234
+
235
+ const methodCache = promiseMethodCache.get(target);
236
+ if (methodCache && methodCache.has(prop)) {
237
+ methodCache.delete(prop);
238
+ }
239
+ return Reflect.deleteProperty(target, prop);
240
+ },
173
241
  ownKeys: Reflect.ownKeys,
174
242
  getOwnPropertyDescriptor: Reflect.getOwnPropertyDescriptor,
175
243
  has: Reflect.has
@@ -352,3 +420,5 @@ export const context = runtime_createLiveBinding("context");
352
420
 
353
421
 
354
422
  export const reference = runtime_createLiveBinding("reference");
423
+
424
+
package/dist/slothlet.mjs CHANGED
@@ -15,9 +15,11 @@
15
15
  */
16
16
 
17
17
 
18
- import fs from "fs/promises";
19
- import path from "path";
20
- import { fileURLToPath, pathToFileURL } from "url";
18
+
19
+
20
+ import fs from "node:fs/promises";
21
+ import path from "node:path";
22
+ import { fileURLToPath, pathToFileURL } from "node:url";
21
23
 
22
24
  import { resolvePathFromCaller } from "@cldmv/slothlet/helpers/resolve-from-caller";
23
25
  import { sanitizePathName } from "@cldmv/slothlet/helpers/sanitize";
@@ -38,12 +40,6 @@ let DEBUG = process.argv.includes("--slothletdebug")
38
40
  : false;
39
41
 
40
42
 
41
- export let _slothlet = new URL(import.meta.url).searchParams.get("_slothlet") || "";
42
-
43
-
44
-
45
-
46
-
47
43
  export const self = {};
48
44
 
49
45
 
@@ -152,7 +148,7 @@ const slothletObject = {
152
148
 
153
149
 
154
150
 
155
-
151
+
156
152
  const imported = await import(modeUrl);
157
153
  if (imported && typeof imported === "object") {
158
154
  this.modes[modeName] = imported.default || imported;
@@ -167,9 +163,6 @@ const slothletObject = {
167
163
 
168
164
  const { entry = import.meta.url, mode = "singleton", api_mode = "auto" } = options ?? {};
169
165
 
170
- _slothlet = new URL(import.meta.url).searchParams.get("_slothlet") || "";
171
-
172
-
173
166
 
174
167
 
175
168
 
@@ -244,8 +237,6 @@ const slothletObject = {
244
237
 
245
238
  }
246
239
 
247
-
248
-
249
240
  if (this.loaded) return this.api;
250
241
  if (this.config.lazy) {
251
242
  this.api = await this.modes.lazy.create.call(this, apiDir, true, this.config.apiDepth || Infinity, 0);
@@ -284,8 +275,6 @@ const slothletObject = {
284
275
 
285
276
  const _boundapi = this.createBoundApi(l_ctxRef.reference);
286
277
 
287
-
288
-
289
278
  mutateLiveBindingFunction(this.boundapi, _boundapi);
290
279
 
291
280
  this.updateBindings(this.context, this.reference, this.boundapi);
@@ -609,8 +598,7 @@ const slothletObject = {
609
598
 
610
599
  async _loadSingleModule(modulePath, rootLevel = false) {
611
600
  const moduleUrl = pathToFileURL(modulePath).href;
612
-
613
-
601
+
614
602
 
615
603
  const module = await import(moduleUrl);
616
604
 
@@ -619,7 +607,6 @@ const slothletObject = {
619
607
 
620
608
 
621
609
 
622
-
623
610
  if (this.config.debug) console.log("module: ", module);
624
611
 
625
612
  if (typeof module.default === "function") {
package/index.cjs CHANGED
@@ -33,8 +33,8 @@ const modPromise = import("@cldmv/slothlet/slothlet");
33
33
  * @returns {Promise<function|object>} The bound API object with live-binding context
34
34
  *
35
35
  * @example // CJS
36
- * const slothlet = require('@cldmv/slothlet');
37
- * const api = await slothlet({ dir: './api', context: { user: 'alice' } });
36
+ * const slothlet = require("@cldmv/slothlet");
37
+ * const api = await slothlet({ dir: "./api", context: { user: "alice" } });
38
38
  * console.log(api.config.username); // Access configuration
39
39
  */
40
40
  async function slothlet(options = {}) {
@@ -75,7 +75,7 @@ module.exports = slothlet;
75
75
  * @type {Function}
76
76
  *
77
77
  * @example // CJS named destructuring
78
- * const { slothlet } = require('@cldmv/slothlet');
79
- * const api = await slothlet({ dir: './api' });
78
+ * const { slothlet } = require("@cldmv/slothlet");
79
+ * const api = await slothlet({ dir: "./api" });
80
80
  */
81
81
  module.exports.slothlet = slothlet; // optional named alias
package/index.mjs CHANGED
@@ -30,7 +30,7 @@
30
30
  * @returns {Promise<function|object>} The bound API object with live-binding context
31
31
  *
32
32
  * @example // ESM
33
- * import slothlet from '@cldmv/slothlet';
33
+ * import slothlet from "@cldmv/slothlet";
34
34
  * const api = await slothlet({ dir: './api', lazy: true });
35
35
  * const result = await api.math.add(2, 3); // 5
36
36
  *
@@ -69,7 +69,7 @@ export default async function slothlet(options = {}) {
69
69
  * @type {Function}
70
70
  *
71
71
  * @example // ESM named import
72
- * import { slothlet } from '@cldmv/slothlet';
72
+ * import { slothlet } from "@cldmv/slothlet";
73
73
  * const api = await slothlet({ dir: './api' });
74
74
  */
75
75
  // Optional named alias
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cldmv/slothlet",
3
- "version": "2.3.0",
3
+ "version": "2.3.2",
4
4
  "moduleVersions": {
5
5
  "lazy": "1.0.0",
6
6
  "eager": "1.0.0"
@@ -139,6 +139,7 @@
139
139
  "@eslint/markdown": "^7.2.0",
140
140
  "@html-eslint/eslint-plugin": "^0.45.0",
141
141
  "@html-eslint/parser": "^0.45.0",
142
+ "@types/node": "^24.9.1",
142
143
  "chalk": "^5.6.0",
143
144
  "dmd": "^7.1.1",
144
145
  "eslint": "^9.33.0",
@@ -3,7 +3,7 @@
3
3
  * @param {Function} fn - Shutdown function to set
4
4
  * @returns {Function} Previously set shutdown function
5
5
  * @example
6
- * const prev = setShutdown(() => console.log('Shutting down'));
6
+ * const prev = setShutdown(() => console.log("Shutting down"));
7
7
  */
8
8
  export function setShutdown(fn: Function): Function;
9
9
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"slothlet_engine.d.mts","sourceRoot":"","sources":["../../../../dist/lib/engine/slothlet_engine.mjs"],"names":[],"mappings":"AAoBA;;;;;;GAMG;AACH,oDAIC;AAED;;;;;;;;;;;;;;GAcG;AACH,yCAZG;IAA2B,KAAK,EAAxB,MAAM;IACc,IAAI,GAAxB,MAAM;IACc,OAAO,GAA3B,MAAM;IACc,SAAS,GAA7B,MAAM;CACd,GAAU,OAAO,CAAC,MAAM,CAAC,CAgC3B;AAyRD,qDA4BC"}
1
+ {"version":3,"file":"slothlet_engine.d.mts","sourceRoot":"","sources":["../../../../dist/lib/engine/slothlet_engine.mjs"],"names":[],"mappings":"AAgCA;;;;;;GAMG;AACH,oDAIC;AAED;;;;;;;;;;;;;;GAcG;AACH,yCAZG;IAA2B,KAAK,EAAxB,MAAM;IACc,IAAI,GAAxB,MAAM;IACc,OAAO,GAA3B,MAAM;IACc,SAAS,GAA7B,MAAM;CACd,GAAU,OAAO,CAAC,MAAM,CAAC,CAgC3B;AAyRD,qDA4BC"}
@@ -1 +1 @@
1
- {"version":3,"file":"slothlet_esm.d.mts","sourceRoot":"","sources":["../../../../dist/lib/engine/slothlet_esm.mjs"],"names":[],"mappings":"AAOA;;;;;;;;;;GAUG;AACH,+CAPW,MAAM,WACN,MAAM,YACN,GAAG,CAAC,MAAM,CAAC,GACT,OAAO,CAAC,MAAM,CAAC,CAkM3B;AAED;;;;GAIG;AACH,mCAHW,MAAM,GACJ,OAAO,CAAC,OAAO,CAAC,CAW5B"}
1
+ {"version":3,"file":"slothlet_esm.d.mts","sourceRoot":"","sources":["../../../../dist/lib/engine/slothlet_esm.mjs"],"names":[],"mappings":"AAmBA;;;;;;;;;;GAUG;AACH,+CAPW,MAAM,WACN,MAAM,YACN,GAAG,CAAC,MAAM,CAAC,GACT,OAAO,CAAC,MAAM,CAAC,CAkM3B;AAED;;;;GAIG;AACH,mCAHW,MAAM,GACJ,OAAO,CAAC,OAAO,CAAC,CAW5B"}
@@ -5,7 +5,7 @@ export function installPortalForSelf(): void;
5
5
  export function asUrl(p: any): any;
6
6
  export function isPlainObject(o: any): boolean;
7
7
  export function guessName(v: any): any;
8
- export function makeNodeishContext(): any;
8
+ export function makeNodeishContext(): vm.Context;
9
9
  /**
10
10
  * Loads a module into a VM context, supporting ESM (mjs), CJS (cjs), or auto-detection.
11
11
  * @param {object} context - The VM context.
@@ -21,4 +21,5 @@ export function marshalArgsReplaceFunctions(value: any, registerCb: any): any;
21
21
  export function reviveArgsReplaceTokens(value: any, invokeCb: any): any;
22
22
  export function containsFunction(value: any): boolean;
23
23
  export const HAS_STM: boolean;
24
+ import vm from "node:vm";
24
25
  //# sourceMappingURL=slothlet_helpers.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"slothlet_helpers.d.mts","sourceRoot":"","sources":["../../../../dist/lib/engine/slothlet_helpers.mjs"],"names":[],"mappings":"AAWA,gDAwBC;AAED,oEAGC;AAED,yEAYC;AAED,6CA6BC;AAED,mCAEC;AAED,+CAEC;AAED,uCAOC;AAQD,0CAyBC;AAED;;;;;;GAMG;AACH,sCALW,MAAM,WACN,MAAM,SACN,MAAM,mBACJ,OAAO,CAAC,MAAM,CAAC,CA2L3B;AAGD,sEAsDC;AAED,8EAYC;AAED,yGAmDC;AAID,8EAaC;AAED,wEAaC;AAED,sDAKC;AAhYD,8BAAiE"}
1
+ {"version":3,"file":"slothlet_helpers.d.mts","sourceRoot":"","sources":["../../../../dist/lib/engine/slothlet_helpers.mjs"],"names":[],"mappings":"AAuBA,gDAwBC;AAED,oEAGC;AAED,yEAYC;AAED,6CA6BC;AAED,mCAEC;AAED,+CAEC;AAED,uCAOC;AAQD,iDAyBC;AAED;;;;;;GAMG;AACH,sCALW,MAAM,WACN,MAAM,SACN,MAAM,mBACJ,OAAO,CAAC,MAAM,CAAC,CA2L3B;AAGD,sEAsDC;AAED,8EAYC;AAED,yGAmDC;AAID,8EAaC;AAED,wEAaC;AAED,sDAKC;AAhYD,8BAAiE;eA3GlD,SAAS"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Enable AsyncLocalStorage context propagation for all EventEmitter instances.
3
+ *
4
+ * @function enableAlsForEventEmitters
5
+ * @package
6
+ * @param {AsyncLocalStorage} [als=sharedALS] - The AsyncLocalStorage instance to use (defaults to slothlet's shared instance)
7
+ *
8
+ * @description
9
+ * Patches EventEmitter.prototype to automatically preserve AsyncLocalStorage context
10
+ * in event listeners using AsyncResource. This ensures that event handlers maintain
11
+ * the same context that was active when they were registered.
12
+ *
13
+ * Uses Node.js AsyncResource API for proper context propagation, following
14
+ * official guidance for AsyncLocalStorage across callback boundaries.
15
+ *
16
+ * @example
17
+ * // Enable ALS for all EventEmitters
18
+ * import { enableAlsForEventEmitters } from "./als-eventemitter.mjs";
19
+ * enableAlsForEventEmitters(als);
20
+ */
21
+ export function enableAlsForEventEmitters(als?: AsyncLocalStorage): void;
22
+ export type AsyncLocalStorage = import("async_hooks").AsyncLocalStorage<any>;
23
+ //# sourceMappingURL=als-eventemitter.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"als-eventemitter.d.mts","sourceRoot":"","sources":["../../../../dist/lib/helpers/als-eventemitter.mjs"],"names":[],"mappings":"AAoCA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,gDAfW,iBAAiB,QAoK3B"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * @Project: @cldmv/slothlet
3
+ * @Filename: /src/lib/helpers/auto-wrap.mjs
4
+ * @Date: 2025-10-21 13:32:36 -07:00 (1761078756)
5
+ * @Author: Nate Hyson <CLDMV>
6
+ * @Email: <Shinrai@users.noreply.github.com>
7
+ * -----
8
+ * @Last modified by: Nate Hyson <CLDMV> (Shinrai@users.noreply.github.com)
9
+ * @Last modified time: 2025-10-22 06:59:17 -07:00 (1761141557)
10
+ * -----
11
+ * @Copyright: Copyright (c) 2013-2025 Catalyzed Motivation Inc. All rights reserved.
12
+ */
13
+ /**
14
+ * @fileoverview Helper for automatically wrapping Node.js EventEmitter instances within API modules.
15
+ * Internal file (not exported in package.json).
16
+ * @module @cldmv/slothlet/src/lib/helpers/auto-wrap
17
+ */
18
+ /**
19
+ * Automatically wrap Node.js EventEmitter constructors when called within slothlet API context.
20
+ * This ensures that EventEmitter instances created inside API modules preserve AsyncLocalStorage context.
21
+ * @function autoWrapEventEmitters
22
+ * @package
23
+ * @param {NetModule} nodeModule - The Node.js module to wrap (e.g., require("node:net"))
24
+ * @returns {NetModule} Wrapped module with auto-wrapping constructors
25
+ *
26
+ * @description
27
+ * Wraps Node.js module functions that return EventEmitter instances so they automatically
28
+ * return wrapped instances when called within slothlet API context.
29
+ *
30
+ * @example
31
+ * // Usage in API modules:
32
+ * import { autoWrapEventEmitters } from "@cldmv/slothlet/src/lib/helpers/auto-wrap";
33
+ * import originalNet from "node:net";
34
+ * const net = autoWrapEventEmitters(originalNet);
35
+ * // Now net.createServer() returns wrapped instances automatically
36
+ */
37
+ export function autoWrapEventEmitters(nodeModule: NetModule): NetModule;
38
+ /**
39
+ * Lazily get the pre-wrapped net module for convenient use in API modules.
40
+ * @function getNet
41
+ * @package
42
+ * @returns {Promise<NetModule>} Promise resolving to the wrapped net module
43
+ * @example
44
+ * const net = await getNet();
45
+ */
46
+ export function getNet(): Promise<NetModule>;
47
+ export type NetModule = typeof import("node:net");
48
+ export type NetServer = import("node:net").Server;
49
+ //# sourceMappingURL=auto-wrap.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auto-wrap.d.mts","sourceRoot":"","sources":["../../../../dist/lib/helpers/auto-wrap.mjs"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH;;;;GAIG;AAEH;;;;;;;;;;;;;;;;;;GAkBG;AACH,kDAdW,SAAS,GACP,SAAS,CA2CrB;AAED;;;;;;;GAOG;AACH,0BAJa,OAAO,CAAC,SAAS,CAAC,CAO9B;wBAGY,cAAc,UAAU,CAAC;wBACzB,OAAO,UAAU,EAAE,MAAM"}
@@ -29,7 +29,7 @@
29
29
  * const stack = getStack(findCaller);
30
30
  * for (const frame of stack) {
31
31
  * const filename = frame?.getFileName?.();
32
- * if (filename && !filename.includes('node_modules')) {
32
+ * if (filename && !filename.includes("node_modules")) {
33
33
  * return filename; // First non-dependency file
34
34
  * }
35
35
  * }
@@ -40,7 +40,7 @@ export function getStack(skipFn?: Function): Array<CallSite>;
40
40
  * @function resolvePathFromCaller
41
41
  * @package
42
42
  * @internal
43
- * @param {string} rel - Relative path to resolve (e.g., '../config.json', './data/file.txt')
43
+ * @param {string} rel - Relative path to resolve (e.g., "../config.json", "./data/file.txt")
44
44
  * @returns {string} Absolute filesystem path with platform-specific separators
45
45
  * @throws {TypeError} When rel parameter is not a string
46
46
  *
@@ -61,24 +61,24 @@ export function getStack(skipFn?: Function): Array<CallSite>;
61
61
  *
62
62
  * @example
63
63
  * // From a file at /project/src/modules/math.mjs
64
- * const configPath = resolvePathFromCaller('../config.json');
64
+ * const configPath = resolvePathFromCaller("../config.json");
65
65
  * // Returns: /project/config.json (absolute filesystem path)
66
66
  *
67
67
  * @example
68
68
  * // Short-circuit cases
69
- * resolvePathFromCaller('file:///absolute/path.txt');
69
+ * resolvePathFromCaller("file:///absolute/path.txt");
70
70
  * // Returns: /absolute/path.txt (converted from URL)
71
71
  *
72
- * resolvePathFromCaller('/already/absolute/path.txt');
72
+ * resolvePathFromCaller("/already/absolute/path.txt");
73
73
  * // Returns: /already/absolute/path.txt (unchanged)
74
74
  *
75
75
  * @example
76
76
  * // Relative resolution from different contexts
77
77
  * // If called from /project/src/lib/utils.mjs:
78
- * resolvePathFromCaller('./helpers/format.js');
78
+ * resolvePathFromCaller("./helpers/format.js");
79
79
  * // Returns: /project/src/lib/helpers/format.js
80
80
  *
81
- * resolvePathFromCaller('../../config/settings.json');
81
+ * resolvePathFromCaller("../../config/settings.json");
82
82
  * // Returns: /project/config/settings.json
83
83
  */
84
84
  export function resolvePathFromCaller(rel: string): string;
@@ -86,7 +86,7 @@ export function resolvePathFromCaller(rel: string): string;
86
86
  * @function resolveUrlFromCaller
87
87
  * @package
88
88
  * @internal
89
- * @param {string} rel - Relative path to resolve (e.g., '../config.json', './data/file.txt')
89
+ * @param {string} rel - Relative path to resolve (e.g., "../config.json", "./data/file.txt")
90
90
  * @returns {string} Absolute file:// URL suitable for dynamic imports and URL operations
91
91
  * @throws {TypeError} When rel parameter is not a string
92
92
  *
@@ -106,27 +106,27 @@ export function resolvePathFromCaller(rel: string): string;
106
106
  *
107
107
  * @example
108
108
  * // From a file at /project/src/modules/math.mjs
109
- * const configUrl = resolveUrlFromCaller('../config.json');
109
+ * const configUrl = resolveUrlFromCaller("../config.json");
110
110
  * // Returns: file:///project/config.json (absolute file:// URL)
111
111
  *
112
112
  * @example
113
113
  * // Short-circuit cases
114
- * resolveUrlFromCaller('file:///absolute/path.txt');
114
+ * resolveUrlFromCaller("file:///absolute/path.txt");
115
115
  * // Returns: file:///absolute/path.txt (unchanged)
116
116
  *
117
- * resolveUrlFromCaller('/already/absolute/path.txt');
117
+ * resolveUrlFromCaller("/already/absolute/path.txt");
118
118
  * // Returns: file:///already/absolute/path.txt (converted to URL)
119
119
  *
120
120
  * @example
121
121
  * // Dynamic ESM import usage
122
- * const modulePath = resolveUrlFromCaller('./dynamic-module.mjs');
122
+ * const modulePath = resolveUrlFromCaller("./dynamic-module.mjs");
123
123
  * const dynamicModule = await import(modulePath);
124
124
  * // Works seamlessly with ESM import() which expects URLs
125
125
  *
126
126
  * @example
127
127
  * // Cross-platform URL handling
128
- * // Unix: resolveUrlFromCaller('../config.json') → file:///project/config.json
129
- * // Windows: resolveUrlFromCaller('../config.json') → file:///C:/project/config.json
128
+ * // Unix: resolveUrlFromCaller("../config.json") → file:///project/config.json
129
+ * // Windows: resolveUrlFromCaller("../config.json") → file:///C:/project/config.json
130
130
  */
131
131
  export function resolveUrlFromCaller(rel: string): string;
132
132
  export function toFsPath(v: any): string | null;
@@ -1 +1 @@
1
- {"version":3,"file":"resolve-from-caller.d.mts","sourceRoot":"","sources":["../../../../dist/lib/helpers/resolve-from-caller.mjs"],"names":[],"mappings":"AAyEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,6CAhCa,KAAK,CAAC,QAAQ,CAAC,CA0C3B;AAqKD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,2CAzCW,MAAM,GACJ,MAAM,CAsDlB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AACH,0CA1CW,MAAM,GACJ,MAAM,CAuDlB;AA/UM,4BAvBI,GAAG,GACD,MAAM,GAAC,IAAI,CAsB+F;;iBAmVzG,MAAY,MAAM,GAAC,SAAS;mBAC5B,MAAY,MAAM,GAAC,SAAS;qBAC5B,MAAY,MAAM,GAAC,SAAS;iBAC5B,MAAY,MAAM,GAAC,SAAS;mBAC5B,MAAY,MAAM,GAAC,SAAS;8BAC5B,MAAY,MAAM,GAAC,SAAS;qBAC5B,MAAY,MAAM,GAAC,SAAS;cAC5B,MAAY,OAAO,GAAC,SAAS;YAC7B,MAAY,OAAO,GAAC,SAAS;mBAC7B,MAAY,OAAO,GAAC,SAAS;gBAC7B,MAAY,OAAO,GAAC,SAAS;aAC7B,MAAY,OAAO,GAAC,SAAS;kBAC7B,MAAY,OAAO,GAAC,SAAS;qBAC7B,MAAY,MAAM,GAAC,SAAS"}
1
+ {"version":3,"file":"resolve-from-caller.d.mts","sourceRoot":"","sources":["../../../../dist/lib/helpers/resolve-from-caller.mjs"],"names":[],"mappings":"AAqFA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,6CAhCa,KAAK,CAAC,QAAQ,CAAC,CA0C3B;AAqKD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,2CAzCW,MAAM,GACJ,MAAM,CAsDlB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AACH,0CA1CW,MAAM,GACJ,MAAM,CAuDlB;AA/UM,4BAvBI,GAAG,GACD,MAAM,GAAC,IAAI,CAsB+F;;iBAmVzG,MAAY,MAAM,GAAC,SAAS;mBAC5B,MAAY,MAAM,GAAC,SAAS;qBAC5B,MAAY,MAAM,GAAC,SAAS;iBAC5B,MAAY,MAAM,GAAC,SAAS;mBAC5B,MAAY,MAAM,GAAC,SAAS;8BAC5B,MAAY,MAAM,GAAC,SAAS;qBAC5B,MAAY,MAAM,GAAC,SAAS;cAC5B,MAAY,OAAO,GAAC,SAAS;YAC7B,MAAY,OAAO,GAAC,SAAS;mBAC7B,MAAY,OAAO,GAAC,SAAS;gBAC7B,MAAY,OAAO,GAAC,SAAS;aAC7B,MAAY,OAAO,GAAC,SAAS;kBAC7B,MAAY,OAAO,GAAC,SAAS;qBAC7B,MAAY,MAAM,GAAC,SAAS"}
@@ -1 +1 @@
1
- {"version":3,"file":"sanitize.d.mts","sourceRoot":"","sources":["../../../../dist/lib/helpers/sanitize.mjs"],"names":[],"mappings":"AAmEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoFG;AACH,wCAjFW,MAAM,SAEd;IAAuB,UAAU,GAAzB,OAAO;IACQ,gBAAgB,GAA/B,OAAO;IACQ,gBAAgB,GAA/B,OAAO;IACO,KAAK,GAC3B;QAA8B,KAAK,GAA3B,MAAM,EAAE;QACc,gBAAgB,GAAtC,MAAM,EAAE;QACc,KAAK,GAA3B,MAAM,EAAE;QACc,KAAK,GAA3B,MAAM,EAAE;KAChB;CAAA,GAAU,MAAM,CAuSlB"}
1
+ {"version":3,"file":"sanitize.d.mts","sourceRoot":"","sources":["../../../../dist/lib/helpers/sanitize.mjs"],"names":[],"mappings":"AAgFA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoFG;AACH,wCAjFW,MAAM,SAEd;IAAuB,UAAU,GAAzB,OAAO;IACQ,gBAAgB,GAA/B,OAAO;IACQ,gBAAgB,GAA/B,OAAO;IACO,KAAK,GAC3B;QAA8B,KAAK,GAA3B,MAAM,EAAE;QACc,gBAAgB,GAAtC,MAAM,EAAE;QACc,KAAK,GAA3B,MAAM,EAAE;QACc,KAAK,GAA3B,MAAM,EAAE;KAChB;CAAA,GAAU,MAAM,CAuSlB"}
@@ -1 +1 @@
1
- {"version":3,"file":"slothlet_eager.d.mts","sourceRoot":"","sources":["../../../../dist/lib/modes/slothlet_eager.mjs"],"names":[],"mappings":"AA8HA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAsDH;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,4BAtBW,MAAM,cACN,OAAO,aACP,MAAM,iBACN,MAAM,GACJ,OAAO,CAAC,MAAM,CAAC,CAqE3B"}
1
+ {"version":3,"file":"slothlet_eager.d.mts","sourceRoot":"","sources":["../../../../dist/lib/modes/slothlet_eager.mjs"],"names":[],"mappings":"AA2IA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAsDH;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,4BAtBW,MAAM,cACN,OAAO,aACP,MAAM,iBACN,MAAM,GACJ,OAAO,CAAC,MAAM,CAAC,CAqE3B"}
@@ -1 +1 @@
1
- {"version":3,"file":"slothlet_lazy.d.mts","sourceRoot":"","sources":["../../../../dist/lib/modes/slothlet_lazy.mjs"],"names":[],"mappings":"AAgJA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,4BAvBW,MAAM,cACN,OAAO,aACP,MAAM,iBACN,MAAM,GACJ,OAAO,CAAC,WAAS,MAAM,CAAC,CAwEpC"}
1
+ {"version":3,"file":"slothlet_lazy.d.mts","sourceRoot":"","sources":["../../../../dist/lib/modes/slothlet_lazy.mjs"],"names":[],"mappings":"AA6JA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,4BAvBW,MAAM,cACN,OAAO,aACP,MAAM,iBACN,MAAM,GACJ,OAAO,CAAC,WAAS,MAAM,CAAC,CAwEpC"}
@@ -1,3 +1,10 @@
1
+ /**
2
+ * Shared AsyncLocalStorage instance for all slothlet instances.
3
+ * Provides unified context management across all EventEmitter wrappers.
4
+ * @type {AsyncLocalStorageType}
5
+ * @public
6
+ */
7
+ export const sharedALS: AsyncLocalStorageType;
1
8
  export function runWithCtx(ctx: object, fn: Function, thisArg: any, args: any[]): any;
2
9
  export function getCtx(): object | null;
3
10
  export function makeWrapper(ctx: object): Function;
@@ -46,4 +53,6 @@ export const context: object;
46
53
  * console.log(reference); // Current reference data
47
54
  */
48
55
  export const reference: object;
56
+ export type AsyncLocalStorageType = AsyncLocalStorage<any>;
57
+ import { AsyncLocalStorage } from "node:async_hooks";
49
58
  //# sourceMappingURL=runtime.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.d.mts","sourceRoot":"","sources":["../../../../dist/lib/runtime/runtime.mjs"],"names":[],"mappings":"AA0CO,gCAdI,MAAM,yBAEN,GAAG,gBAED,GAAG,CA6Bf;AAiBM,0BAZM,MAAM,GAAC,IAAI,CAY0B;AA8K3C,iCAjBI,MAAM,YAwEhB;AA4RD;;;;;;;;;;;;;GAaG;AACH,mBATU,WAAS,MAAM,CAS6B;AAEtD;;;;;;;;;;;;;GAaG;AACH,sBATU,MAAM,CAS4C;AAE5D;;;;;;;;;;;;;GAaG;AACH,wBATU,MAAM,CASgD"}
1
+ {"version":3,"file":"runtime.d.mts","sourceRoot":"","sources":["../../../../dist/lib/runtime/runtime.mjs"],"names":[],"mappings":"AAuCA;;;;;GAKG;AACH,wBAHU,qBAAqB,CAGkB;AAsB1C,gCAdI,MAAM,yBAEN,GAAG,gBAED,GAAG,CA6Bf;AAiBM,0BAZM,MAAM,GAAC,IAAI,CAY0B;AAiL3C,iCAjBI,MAAM,YAgIhB;AA4RD;;;;;;;;;;;;;GAaG;AACH,mBATU,WAAS,MAAM,CAS6B;AAEtD;;;;;;;;;;;;;GAaG;AACH,sBATU,MAAM,CAS4C;AAE5D;;;;;;;;;;;;;GAaG;AACH,wBATU,MAAM,CASgD;;kCAhrB9B,kBAAkB"}
@@ -9,13 +9,6 @@
9
9
  * mutateLiveBindingFunction(boundapi, newApi);
10
10
  */
11
11
  export function mutateLiveBindingFunction(target: Function | object, source: Function | object): void;
12
- /**
13
- * The shared _slothlet parameter for live binding coordination.
14
- * @type {string}
15
- * @private
16
- * @internal
17
- */
18
- export let _slothlet: string;
19
12
  /**
20
13
  * Live-binding reference to the current API instance.
21
14
  * This is updated whenever a new API instance is created.
@@ -86,7 +79,7 @@ export type SlothletOptions = {
86
79
  api_mode?: string;
87
80
  /**
88
81
  * - Context data object injected into live-binding `context` reference.
89
- * - Available to all loaded modules via `import { context } from '@cldmv/slothlet/runtime'`. Useful for request data,
82
+ * - Available to all loaded modules via `import { context } from "@cldmv/slothlet/runtime"`. Useful for request data,
90
83
  * - user sessions, environment configs, etc.
91
84
  */
92
85
  context?: object;
@@ -1 +1 @@
1
- {"version":3,"file":"slothlet.d.mts","sourceRoot":"","sources":["../../dist/slothlet.mjs"],"names":[],"mappings":"AAi5CA;;;;;;;;;GASG;AACH,kDARW,WAAS,MAAM,UACf,WAAS,MAAM,QAwCzB;AAzzCD;;;;;GAKG;AACH,sBAJU,MAAM,CAIoE;AAKpF;;;;;;;GAOG;AACH,mBAJU,MAAM,CAIO;AAEvB;;;;;GAKG;AACH,sBAJU,MAAM,CAIU;AAE1B;;;;;GAKG;AACH,wBAJU,MAAM,CAIY;;;;;;;;;UAiyCd,MAAM;;;;;;WAIN,OAAO;;;;;;;eAGP,MAAM;;;;;;;;YAIN,OAAO;;;;;;;;WAKP,MAAM;;;;;;;eAKN,MAAM;;;;;;cAIN,MAAM;;;;;;gBAGN,MAAM;;;;;;eAMjB;QAA8B,UAAU,GAA7B,OAAO;QACY,gBAAgB,GAAnC,OAAO;QACY,gBAAgB,GAAnC,OAAO;QACW,KAAK,GAClC;YAAqC,KAAK,GAA/B,MAAM,EAAE;YACkB,gBAAgB,GAA1C,MAAM,EAAE;YACkB,KAAK,GAA/B,MAAM,EAAE;YACkB,KAAK,GAA/B,MAAM,EAAE;SACrB;KAAA;;AAz0CD;;;;;;;;GAQG;AACH,mCAJW,eAAe,GACb,OAAO,CAAC,WAAS,MAAM,CAAC,CAiCpC"}
1
+ {"version":3,"file":"slothlet.d.mts","sourceRoot":"","sources":["../../dist/slothlet.mjs"],"names":[],"mappings":"AA04CA;;;;;;;;;GASG;AACH,kDARW,WAAS,MAAM,UACf,WAAS,MAAM,QAwCzB;AAryCD;;;;;;;GAOG;AACH,mBAJU,MAAM,CAIO;AAEvB;;;;;GAKG;AACH,sBAJU,MAAM,CAIU;AAE1B;;;;;GAKG;AACH,wBAJU,MAAM,CAIY;;;;;;;;;UAwxCd,MAAM;;;;;;WAIN,OAAO;;;;;;;eAGP,MAAM;;;;;;;;YAIN,OAAO;;;;;;;;WAKP,MAAM;;;;;;;eAKN,MAAM;;;;;;cAIN,MAAM;;;;;;gBAGN,MAAM;;;;;;eAMjB;QAA8B,UAAU,GAA7B,OAAO;QACY,gBAAgB,GAAnC,OAAO;QACY,gBAAgB,GAAnC,OAAO;QACW,KAAK,GAClC;YAAqC,KAAK,GAA/B,MAAM,EAAE;YACkB,gBAAgB,GAA1C,MAAM,EAAE;YACkB,KAAK,GAA/B,MAAM,EAAE;YACkB,KAAK,GAA/B,MAAM,EAAE;SACrB;KAAA;;AAh0CD;;;;;;;;GAQG;AACH,mCAJW,eAAe,GACb,OAAO,CAAC,WAAS,MAAM,CAAC,CAiCpC"}
package/types/index.d.mts CHANGED
@@ -11,7 +11,6 @@ export type * from "./dist/slothlet.d.mts";
11
11
  export * from "./dist/slothlet.mts";
12
12
 
13
13
  // Auto-generated named export declarations (these override the re-export above)
14
- export const _slothlet: any;
15
14
  export const context: any;
16
15
  export const mutateLiveBindingFunction: any;
17
16
  export const reference: any;