moost 0.6.41 → 0.6.42

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -48,7 +48,7 @@ let stamped = false;
48
48
  if (stamped) return;
49
49
  stamped = true;
50
50
  stampModuleIdentity({
51
- version: "0.6.41",
51
+ version: "0.6.42",
52
52
  path: typeof __filename === "string" ? __filename : require("url").pathToFileURL(__filename).href
53
53
  });
54
54
  }
@@ -446,7 +446,13 @@ function nextScopeId() {
446
446
  }
447
447
  return `__moost_${_scopeChar}_${++_scopeNum}`;
448
448
  }
449
- /** Composable returning the moost scope ID for the current event. Generates on first call, caches for subsequent calls. */ const useScopeId = (0, _wooksjs_event_core.defineWook)(() => nextScopeId());
449
+ const scopeIdSlot = (0, _wooksjs_event_core.cached)(() => nextScopeId());
450
+ /**
451
+ * Composable returning the moost DI scope ID of the current event. Generated on first call
452
+ * and cached on the event context itself — never inherited from a parent context, so a child
453
+ * event (a workflow run started with `eventContext`, a WebSocket message) owns its scope
454
+ * instead of sharing, and later releasing, its parent's.
455
+ */ const useScopeId = (ctx) => (ctx ?? (0, _wooksjs_event_core.current)()).getOwn(scopeIdSlot);
450
456
  /** Registers a DI scope for the given ID and returns an unscope function. */ function registerEventScope(scopeId) {
451
457
  const infact = getMoostInfact();
452
458
  infact.registerScope(scopeId);
@@ -454,12 +460,42 @@ function nextScopeId() {
454
460
  infact.unregisterScope(scopeId);
455
461
  };
456
462
  }
463
+ const noop = () => {};
464
+ /**
465
+ * Registers an event's DI scope, held by its handler lifecycle and, with `adapterHolds`, by
466
+ * the adapter too. Each release is idempotent; the scope is dropped once every holder let go,
467
+ * so an adapter signal that fires early (a client disconnect mid-handler) cannot pull the
468
+ * scope from under a running handler. Built outside the handler closure so a long-lived
469
+ * adapter listener (the response 'close' of a streamed body) retains only the scope.
470
+ */ function holdEventScope(scopeId, adapterHolds) {
471
+ const drop = registerEventScope(scopeId);
472
+ let holders = adapterHolds ? 2 : 1;
473
+ const hold = () => {
474
+ let held = true;
475
+ return () => {
476
+ if (held) {
477
+ held = false;
478
+ if (--holders === 0) drop();
479
+ }
480
+ };
481
+ };
482
+ const releaseLifecycle = hold();
483
+ return {
484
+ releaseLifecycle,
485
+ failLifecycle: (error) => {
486
+ releaseLifecycle();
487
+ throw error;
488
+ },
489
+ unscope: adapterHolds ? hold() : noop
490
+ };
491
+ }
457
492
  /**
458
493
  * Creates the complete event handler lifecycle processor used by adapters.
459
494
  * Handles scope registration, controller resolution, interceptors, argument resolution,
460
495
  * handler invocation, and cleanup — optimised for sync-first execution.
461
496
  */ function defineMoostEventHandler(options) {
462
497
  const ci = (0, _wooksjs_event_core.getContextInjector)();
498
+ const manualUnscope = !!options.manualUnscope;
463
499
  const handlerSpanName = `Handler:${options.targetPath}`;
464
500
  const handlerAttrs = {
465
501
  "moost.handler": options.controllerMethod || "",
@@ -469,7 +505,7 @@ function nextScopeId() {
469
505
  const ctx = (0, _wooksjs_event_core.current)();
470
506
  const scopeId = useScopeId(ctx);
471
507
  const logger = (0, _wooksjs_event_core.useLogger)(options.loggerTitle, ctx);
472
- const unscope = registerEventScope(scopeId);
508
+ const { unscope, releaseLifecycle, failLifecycle } = holdEventScope(scopeId, manualUnscope);
473
509
  let response;
474
510
  let hookOptions;
475
511
  function getHookOptions() {
@@ -485,14 +521,17 @@ function nextScopeId() {
485
521
  let interceptorHandler;
486
522
  let raise = false;
487
523
  try {
524
+ const result = start();
525
+ return isThenable(result) ? result.then(void 0, failLifecycle) : result;
526
+ } catch (error) {
527
+ return failLifecycle(error);
528
+ }
529
+ function start() {
488
530
  if (options.hooks?.init) {
489
531
  const hookResult = options.hooks.init(getHookOptions());
490
532
  if (isThenable(hookResult)) return hookResult.then(afterInit);
491
533
  }
492
534
  return afterInit();
493
- } catch (error) {
494
- if (!options.manualUnscope) unscope();
495
- throw error;
496
535
  }
497
536
  function afterInit() {
498
537
  const instanceResult = options.getControllerInstance();
@@ -576,7 +615,6 @@ function nextScopeId() {
576
615
  return finalize();
577
616
  }, (error) => {
578
617
  if (options.logErrors) logger.error(String(error));
579
- if (!options.manualUnscope) unscope();
580
618
  throw error;
581
619
  });
582
620
  response = afterResult;
@@ -585,7 +623,7 @@ function nextScopeId() {
585
623
  return finalize();
586
624
  }
587
625
  function finalize() {
588
- if (!options.manualUnscope) unscope();
626
+ releaseLifecycle();
589
627
  if (options.hooks?.end) {
590
628
  const endResult = options.hooks.end(getHookOptions());
591
629
  if (isThenable(endResult)) return endResult.then(() => {
package/dist/index.d.ts CHANGED
@@ -1,4 +1,3 @@
1
- import * as _wooksjs_event_core from '@wooksjs/event-core';
2
1
  import { EventContext, Logger, Key } from '@wooksjs/event-core';
3
2
  export { Cached, ContextInjector, EventContext, EventContextOptions, Key, Logger, cached, createEventContext, current, eventTypeKey, getContextInjector, key, replaceContextInjector, resetContextInjector, run, useLogger } from '@wooksjs/event-core';
4
3
  import { TProvideRegistry, TReplaceRegistry, Infact, TProvideFn } from '@prostojs/infact';
@@ -1288,8 +1287,13 @@ interface TMoostEventHandlerOptions<T> {
1288
1287
  controllerPrefix?: string;
1289
1288
  handlerType: string;
1290
1289
  }
1291
- /** Composable returning the moost scope ID for the current event. Generates on first call, caches for subsequent calls. */
1292
- declare const useScopeId: _wooksjs_event_core.WookComposable<string>;
1290
+ /**
1291
+ * Composable returning the moost DI scope ID of the current event. Generated on first call
1292
+ * and cached on the event context itself — never inherited from a parent context, so a child
1293
+ * event (a workflow run started with `eventContext`, a WebSocket message) owns its scope
1294
+ * instead of sharing, and later releasing, its parent's.
1295
+ */
1296
+ declare const useScopeId: (ctx?: EventContext) => string;
1293
1297
  /** Registers a DI scope for the given ID and returns an unscope function. */
1294
1298
  declare function registerEventScope(scopeId: string): () => void;
1295
1299
  /**
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { ContextInjector, cached, createEventContext, createEventContext as createEventContext$1, current, current as current$1, defineWook, eventTypeKey, getContextInjector, getContextInjector as getContextInjector$1, key, key as key$1, replaceContextInjector, resetContextInjector, run, useLogger, useLogger as useLogger$1, useRouteParams } from "@wooksjs/event-core";
1
+ import { ContextInjector, cached, cached as cached$1, createEventContext, createEventContext as createEventContext$1, current, current as current$1, eventTypeKey, getContextInjector, getContextInjector as getContextInjector$1, key, key as key$1, replaceContextInjector, resetContextInjector, run, useLogger, useLogger as useLogger$1, useRouteParams } from "@wooksjs/event-core";
2
2
  import { Infact, createProvideRegistry, createProvideRegistry as createProvideRegistry$1, createReplaceRegistry, createReplaceRegistry as createReplaceRegistry$1, getClassKey, getClassKey as getClassKey$1 } from "@prostojs/infact";
3
3
  import { Mate, getConstructor, getConstructor as getConstructor$1, isConstructor, isConstructor as isConstructor$1 } from "@prostojs/mate";
4
4
  import { ProstoLogger, ProstoLogger as ProstoLogger$1, coloredConsole, createConsoleTransort } from "@prostojs/logger";
@@ -47,7 +47,7 @@ let stamped = false;
47
47
  if (stamped) return;
48
48
  stamped = true;
49
49
  stampModuleIdentity({
50
- version: "0.6.41",
50
+ version: "0.6.42",
51
51
  path: typeof __filename === "string" ? __filename : import.meta.url
52
52
  });
53
53
  }
@@ -445,7 +445,13 @@ function nextScopeId() {
445
445
  }
446
446
  return `__moost_${_scopeChar}_${++_scopeNum}`;
447
447
  }
448
- /** Composable returning the moost scope ID for the current event. Generates on first call, caches for subsequent calls. */ const useScopeId = defineWook(() => nextScopeId());
448
+ const scopeIdSlot = cached$1(() => nextScopeId());
449
+ /**
450
+ * Composable returning the moost DI scope ID of the current event. Generated on first call
451
+ * and cached on the event context itself — never inherited from a parent context, so a child
452
+ * event (a workflow run started with `eventContext`, a WebSocket message) owns its scope
453
+ * instead of sharing, and later releasing, its parent's.
454
+ */ const useScopeId = (ctx) => (ctx ?? current$1()).getOwn(scopeIdSlot);
449
455
  /** Registers a DI scope for the given ID and returns an unscope function. */ function registerEventScope(scopeId) {
450
456
  const infact = getMoostInfact();
451
457
  infact.registerScope(scopeId);
@@ -453,12 +459,42 @@ function nextScopeId() {
453
459
  infact.unregisterScope(scopeId);
454
460
  };
455
461
  }
462
+ const noop = () => {};
463
+ /**
464
+ * Registers an event's DI scope, held by its handler lifecycle and, with `adapterHolds`, by
465
+ * the adapter too. Each release is idempotent; the scope is dropped once every holder let go,
466
+ * so an adapter signal that fires early (a client disconnect mid-handler) cannot pull the
467
+ * scope from under a running handler. Built outside the handler closure so a long-lived
468
+ * adapter listener (the response 'close' of a streamed body) retains only the scope.
469
+ */ function holdEventScope(scopeId, adapterHolds) {
470
+ const drop = registerEventScope(scopeId);
471
+ let holders = adapterHolds ? 2 : 1;
472
+ const hold = () => {
473
+ let held = true;
474
+ return () => {
475
+ if (held) {
476
+ held = false;
477
+ if (--holders === 0) drop();
478
+ }
479
+ };
480
+ };
481
+ const releaseLifecycle = hold();
482
+ return {
483
+ releaseLifecycle,
484
+ failLifecycle: (error) => {
485
+ releaseLifecycle();
486
+ throw error;
487
+ },
488
+ unscope: adapterHolds ? hold() : noop
489
+ };
490
+ }
456
491
  /**
457
492
  * Creates the complete event handler lifecycle processor used by adapters.
458
493
  * Handles scope registration, controller resolution, interceptors, argument resolution,
459
494
  * handler invocation, and cleanup — optimised for sync-first execution.
460
495
  */ function defineMoostEventHandler(options) {
461
496
  const ci = getContextInjector$1();
497
+ const manualUnscope = !!options.manualUnscope;
462
498
  const handlerSpanName = `Handler:${options.targetPath}`;
463
499
  const handlerAttrs = {
464
500
  "moost.handler": options.controllerMethod || "",
@@ -468,7 +504,7 @@ function nextScopeId() {
468
504
  const ctx = current$1();
469
505
  const scopeId = useScopeId(ctx);
470
506
  const logger = useLogger$1(options.loggerTitle, ctx);
471
- const unscope = registerEventScope(scopeId);
507
+ const { unscope, releaseLifecycle, failLifecycle } = holdEventScope(scopeId, manualUnscope);
472
508
  let response;
473
509
  let hookOptions;
474
510
  function getHookOptions() {
@@ -484,14 +520,17 @@ function nextScopeId() {
484
520
  let interceptorHandler;
485
521
  let raise = false;
486
522
  try {
523
+ const result = start();
524
+ return isThenable(result) ? result.then(void 0, failLifecycle) : result;
525
+ } catch (error) {
526
+ return failLifecycle(error);
527
+ }
528
+ function start() {
487
529
  if (options.hooks?.init) {
488
530
  const hookResult = options.hooks.init(getHookOptions());
489
531
  if (isThenable(hookResult)) return hookResult.then(afterInit);
490
532
  }
491
533
  return afterInit();
492
- } catch (error) {
493
- if (!options.manualUnscope) unscope();
494
- throw error;
495
534
  }
496
535
  function afterInit() {
497
536
  const instanceResult = options.getControllerInstance();
@@ -575,7 +614,6 @@ function nextScopeId() {
575
614
  return finalize();
576
615
  }, (error) => {
577
616
  if (options.logErrors) logger.error(String(error));
578
- if (!options.manualUnscope) unscope();
579
617
  throw error;
580
618
  });
581
619
  response = afterResult;
@@ -584,7 +622,7 @@ function nextScopeId() {
584
622
  return finalize();
585
623
  }
586
624
  function finalize() {
587
- if (!options.manualUnscope) unscope();
625
+ releaseLifecycle();
588
626
  if (options.hooks?.end) {
589
627
  const endResult = options.hooks.end(getHookOptions());
590
628
  if (isThenable(endResult)) return endResult.then(() => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "moost",
3
- "version": "0.6.41",
3
+ "version": "0.6.42",
4
4
  "description": "moost",
5
5
  "keywords": [
6
6
  "composables",
@@ -41,15 +41,15 @@
41
41
  "@prostojs/infact": "^0.6.0",
42
42
  "@prostojs/logger": "^0.4.3",
43
43
  "@prostojs/mate": "^0.5.0",
44
- "@wooksjs/event-core": "^0.7.24",
44
+ "@wooksjs/event-core": "^0.7.25",
45
45
  "hookable": "^5.5.3",
46
- "wooks": "^0.7.24"
46
+ "wooks": "^0.7.25"
47
47
  },
48
48
  "devDependencies": {
49
- "@wooksjs/event-http": "^0.7.24",
50
- "@wooksjs/http-body": "^0.7.24",
49
+ "@wooksjs/event-http": "^0.7.25",
50
+ "@wooksjs/http-body": "^0.7.25",
51
51
  "vitest": "3.2.7",
52
- "@moostjs/event-http": "^0.6.41"
52
+ "@moostjs/event-http": "^0.6.42"
53
53
  },
54
54
  "scripts": {
55
55
  "pub": "pnpm publish --access public",