@moostjs/event-http 0.6.42 → 0.6.44

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
@@ -540,8 +540,14 @@ function _define_property(obj, key, value) {
540
540
  else obj[key] = value;
541
541
  return obj;
542
542
  }
543
+ /** Marks the child context of {@link MoostHttp.invoke}. */ const invocationKey = (0, moost.globalKey)("moost-http.invocation");
543
544
  const holdScopeUntilResponseCloses = { init: ({ unscope }) => {
544
- const res = (0, _wooksjs_event_http.useResponse)().getRawRes(true);
545
+ const ctx = (0, moost.current)();
546
+ if (ctx.hasOwn(invocationKey)) {
547
+ unscope();
548
+ return;
549
+ }
550
+ const res = (0, _wooksjs_event_http.useResponse)(ctx).getRawRes(true);
545
551
  if (res.closed) unscope();
546
552
  else res.once("close", unscope);
547
553
  } };
@@ -605,6 +611,60 @@ const LOGGER_TITLE = "moost-http";
605
611
  */ withHttpContext(req, res, fn) {
606
612
  return this.httpApp.withHttpContext(req, res, fn);
607
613
  }
614
+ /**
615
+ * Runs the route matching `method` + `path` inside the CURRENT HTTP event — its whole moost
616
+ * pipeline (DI scope, guards and other interceptors, argument resolution, pipes, handler) —
617
+ * and resolves to the handler's return value, or rejects with its error. Nothing is written
618
+ * to the HTTP response.
619
+ *
620
+ * The route runs in a copy-on-write child of the current event: it reads the caller's
621
+ * request, headers and authorization through, but sees its own body (`opts.body`), its own
622
+ * route params, its own controller context and its own `FOR_EVENT` DI scope (released when
623
+ * the handler settles). Status, headers and cookies it sets go to a detached response and
624
+ * are discarded.
625
+ *
626
+ * Use it to delegate work to another controller's route without a network round-trip or
627
+ * re-sending credentials. Rejects with `HttpError(404)` when no route matches.
628
+ *
629
+ * @example
630
+ * ```ts
631
+ * const http = await useControllerContext().instantiate(MoostHttp)
632
+ * const summary = await http.invoke('POST', '/issues/actions/close', { body: { ids } })
633
+ * ```
634
+ */ invoke(method, path, opts) {
635
+ const parent = (0, moost.current)();
636
+ const caller = parent.has(_wooksjs_event_http.httpKind.keys.response) ? parent.get(_wooksjs_event_http.httpKind.keys.response) : void 0;
637
+ if (!caller) throw new Error("MoostHttp.invoke() must be called inside an HTTP event");
638
+ const child = (0, moost.forkEventContext)({
639
+ parent,
640
+ isolate: opts?.isolate
641
+ });
642
+ child.setOwn(invocationKey, true);
643
+ const ResponseCtor = caller.constructor;
644
+ child.setOwn(_wooksjs_event_http.httpKind.keys.response, new ResponseCtor(caller.getRawRes(true), parent.get(_wooksjs_event_http.httpKind.keys.req), parent.logger, void 0, true));
645
+ (0, _wooksjs_http_body.seedBody)(child, opts?.body, {
646
+ raw: opts?.rawBody,
647
+ contentType: opts?.contentType
648
+ });
649
+ opts?.prepare?.(child);
650
+ return (0, moost.run)(child, async () => {
651
+ const handlers = this.httpApp.getWooks().lookupHandlers(method, path, child);
652
+ if (!handlers?.length) throw new _wooksjs_event_http.HttpError(404, `No route for ${method} ${path}`);
653
+ let failure;
654
+ for (const handler of handlers) {
655
+ let result;
656
+ try {
657
+ result = await handler();
658
+ } catch (error) {
659
+ failure = error;
660
+ continue;
661
+ }
662
+ if (result instanceof Error) throw result;
663
+ return result;
664
+ }
665
+ throw failure;
666
+ });
667
+ }
608
668
  listen(port, hostname, backlog, listeningListener) {
609
669
  return this.httpApp.listen(port, hostname, backlog, listeningListener);
610
670
  }
@@ -694,7 +754,7 @@ const LOGGER_TITLE = "moost-http";
694
754
  image: "https://moost.org/moost-full-logo.svg",
695
755
  link: "https://moost.org/",
696
756
  poweredBy: "moostjs",
697
- version: "0.6.42"
757
+ version: "0.6.44"
698
758
  });
699
759
  if (httpApp && httpApp instanceof _wooksjs_event_http.WooksHttp) this.httpApp = httpApp;
700
760
  else if (httpApp) this.httpApp = (0, _wooksjs_event_http.createHttpApp)({
@@ -704,6 +764,7 @@ const LOGGER_TITLE = "moost-http";
704
764
  else this.httpApp = (0, _wooksjs_event_http.createHttpApp)({ onNotFound: this.onNotFound.bind(this) });
705
765
  }
706
766
  };
767
+ /** Names this adapter for DI independently of class identity (see `MOOST_ADAPTER_BRAND`). */ _define_property(MoostHttp, moost.MOOST_ADAPTER_BRAND, "@moostjs/event-http/MoostHttp");
707
768
 
708
769
  //#endregion
709
770
  //#region packages/event-http/src/local-fetch.ts
package/dist/index.d.ts CHANGED
@@ -1,9 +1,10 @@
1
1
  import * as moost from 'moost';
2
- import { TInterceptorPriority, TOvertakeFn, TInterceptorDef, TClassConstructor, TMoostAdapter, Moost, TConsoleBase, TMoostAdapterOptions } from 'moost';
2
+ import { TInterceptorPriority, TOvertakeFn, TInterceptorDef, TClassConstructor, TMoostAdapter, MOOST_ADAPTER_BRAND, TIsolatedSlot, EventContext, Moost, TConsoleBase, TMoostAdapterOptions } from 'moost';
3
3
  import * as _wooksjs_event_http from '@wooksjs/event-http';
4
4
  import { TCookieAttributes as TCookieAttributes$1, TCookieAttributesInput, WooksHttp, TWooksHttpOptions } from '@wooksjs/event-http';
5
5
  export { HttpError, TCacheControl, TCookieAttributesInput, TSetCookieData, httpKind, useHttpContext } from '@wooksjs/event-http';
6
6
  import { IncomingMessage, ServerResponse } from 'http';
7
+ import { Buffer } from 'buffer';
7
8
  import { ListenOptions } from 'net';
8
9
 
9
10
  /** Bearer token transport configuration for auth guards. */
@@ -371,6 +372,29 @@ interface THttpHandlerMeta {
371
372
  method: string;
372
373
  path: string;
373
374
  }
375
+ /** Options for {@link MoostHttp.invoke}. */
376
+ interface TMoostHttpInvokeOptions {
377
+ /**
378
+ * The parsed request body the invoked route sees (`@Body()`, `useBody().parseBody()`).
379
+ * Without `body` / `rawBody` the route sees an empty body — never the calling request's.
380
+ */
381
+ body?: unknown;
382
+ /** The raw body bytes (`@RawBody()`, `rawBody()`). Default: derived from `body` (JSON for objects). */
383
+ rawBody?: Buffer | string;
384
+ /** The content type `useBody().is()` checks. Default: derived from `body` (`application/json` for objects). */
385
+ contentType?: string;
386
+ /**
387
+ * Slots (or `defineWook` composables) of the calling event that the invoked route must not
388
+ * read through — per-event state the calling handler computed and the route must compute
389
+ * for itself.
390
+ */
391
+ isolate?: Iterable<TIsolatedSlot>;
392
+ /**
393
+ * Called with the route's child context before the route runs — seed extra slots, or keep a
394
+ * reference to read what the route left in it once `invoke()` settled.
395
+ */
396
+ prepare?: (ctx: EventContext) => void;
397
+ }
374
398
  /**
375
399
  * ## Moost HTTP Adapter
376
400
  *
@@ -397,6 +421,8 @@ interface THttpHandlerMeta {
397
421
  * ```
398
422
  */
399
423
  declare class MoostHttp implements TMoostAdapter<THttpHandlerMeta> {
424
+ /** Names this adapter for DI independently of class identity (see `MOOST_ADAPTER_BRAND`). */
425
+ static readonly [MOOST_ADAPTER_BRAND] = "@moostjs/event-http/MoostHttp";
400
426
  readonly name = "http";
401
427
  protected httpApp: WooksHttp;
402
428
  constructor(httpApp?: WooksHttp | TWooksHttpOptions);
@@ -430,6 +456,28 @@ declare class MoostHttp implements TMoostAdapter<THttpHandlerMeta> {
430
456
  result: Awaited<T>;
431
457
  response: _wooksjs_event_http.HttpResponse;
432
458
  }>;
459
+ /**
460
+ * Runs the route matching `method` + `path` inside the CURRENT HTTP event — its whole moost
461
+ * pipeline (DI scope, guards and other interceptors, argument resolution, pipes, handler) —
462
+ * and resolves to the handler's return value, or rejects with its error. Nothing is written
463
+ * to the HTTP response.
464
+ *
465
+ * The route runs in a copy-on-write child of the current event: it reads the caller's
466
+ * request, headers and authorization through, but sees its own body (`opts.body`), its own
467
+ * route params, its own controller context and its own `FOR_EVENT` DI scope (released when
468
+ * the handler settles). Status, headers and cookies it sets go to a detached response and
469
+ * are discarded.
470
+ *
471
+ * Use it to delegate work to another controller's route without a network round-trip or
472
+ * re-sending credentials. Rejects with `HttpError(404)` when no route matches.
473
+ *
474
+ * @example
475
+ * ```ts
476
+ * const http = await useControllerContext().instantiate(MoostHttp)
477
+ * const summary = await http.invoke('POST', '/issues/actions/close', { body: { ids } })
478
+ * ```
479
+ */
480
+ invoke<R = unknown>(method: string, path: string, opts?: TMoostHttpInvokeOptions): Promise<R>;
433
481
  listen(port?: number, hostname?: string, backlog?: number, listeningListener?: () => void): Promise<void>;
434
482
  listen(port?: number, hostname?: string, listeningListener?: () => void): Promise<void>;
435
483
  listen(port?: number, backlog?: number, listeningListener?: () => void): Promise<void>;
@@ -479,4 +527,4 @@ declare class MoostHttp implements TMoostAdapter<THttpHandlerMeta> {
479
527
  declare function enableLocalFetch(http: MoostHttp): () => void;
480
528
 
481
529
  export { All, AuthGuard, Authenticate, Authorization, Body, BodyReadTimeoutMs, BodySizeLimit, CompressedBodySizeLimit, Cookie, CookieAttrsRef, CookieRef, Delete, Get, Header, HeaderRef, HttpMethod, Ip, IpList, Method, MoostHttp, Patch, Post, Put, Query, RawBody, Req, ReqId, Res, SetCookie, SetHeader, SetStatus, StatusRef, Upgrade, Url, defineAuthGuard, enableLocalFetch, extractTransports, globalBodyReadTimeoutMs, globalBodySizeLimit, globalCompressedBodySizeLimit };
482
- export type { TAuthGuardClass, TAuthGuardDef, TAuthGuardHandler, TAuthTransportApiKey, TAuthTransportBasic, TAuthTransportBearer, TAuthTransportCookie, TAuthTransportDeclaration, TAuthTransportValues, TCookieAttributes, TCookieRef, THeaderRef, THttpHandlerMeta, TStatusRef };
530
+ export type { TAuthGuardClass, TAuthGuardDef, TAuthGuardHandler, TAuthTransportApiKey, TAuthTransportBasic, TAuthTransportBearer, TAuthTransportCookie, TAuthTransportDeclaration, TAuthTransportValues, TCookieAttributes, TCookieRef, THeaderRef, THttpHandlerMeta, TMoostHttpInvokeOptions, TStatusRef };
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import { current } from "@wooksjs/event-core";
2
- import { HttpError, HttpError as HttpError$1, WooksHttp, WooksHttpResponse, createHttpApp, httpKind, useAuthorization, useCookies, useHeaders, useHttpContext, useRequest, useResponse, useUrlParams } from "@wooksjs/event-http";
3
- import { Before, Intercept, Interceptor, Overtake, Resolve, TInterceptorPriority, defineBeforeInterceptor, defineMoostEventHandler, getMoostMate } from "moost";
4
- import { useBody } from "@wooksjs/http-body";
2
+ import { HttpError, HttpError as HttpError$1, WooksHttp, WooksHttpResponse, createHttpApp, httpKind, httpKind as httpKind$1, useAuthorization, useCookies, useHeaders, useHttpContext, useRequest, useResponse, useUrlParams } from "@wooksjs/event-http";
3
+ import { Before, Intercept, Interceptor, MOOST_ADAPTER_BRAND, Overtake, Resolve, TInterceptorPriority, current as current$1, defineBeforeInterceptor, defineMoostEventHandler, forkEventContext, getMoostMate, globalKey, run } from "moost";
4
+ import { seedBody, useBody } from "@wooksjs/http-body";
5
5
  import { createProvideRegistry } from "@prostojs/infact";
6
6
  import { Server } from "http";
7
7
  import { Server as Server$1 } from "https";
@@ -539,8 +539,14 @@ function _define_property(obj, key, value) {
539
539
  else obj[key] = value;
540
540
  return obj;
541
541
  }
542
+ /** Marks the child context of {@link MoostHttp.invoke}. */ const invocationKey = globalKey("moost-http.invocation");
542
543
  const holdScopeUntilResponseCloses = { init: ({ unscope }) => {
543
- const res = useResponse().getRawRes(true);
544
+ const ctx = current$1();
545
+ if (ctx.hasOwn(invocationKey)) {
546
+ unscope();
547
+ return;
548
+ }
549
+ const res = useResponse(ctx).getRawRes(true);
544
550
  if (res.closed) unscope();
545
551
  else res.once("close", unscope);
546
552
  } };
@@ -604,6 +610,60 @@ const LOGGER_TITLE = "moost-http";
604
610
  */ withHttpContext(req, res, fn) {
605
611
  return this.httpApp.withHttpContext(req, res, fn);
606
612
  }
613
+ /**
614
+ * Runs the route matching `method` + `path` inside the CURRENT HTTP event — its whole moost
615
+ * pipeline (DI scope, guards and other interceptors, argument resolution, pipes, handler) —
616
+ * and resolves to the handler's return value, or rejects with its error. Nothing is written
617
+ * to the HTTP response.
618
+ *
619
+ * The route runs in a copy-on-write child of the current event: it reads the caller's
620
+ * request, headers and authorization through, but sees its own body (`opts.body`), its own
621
+ * route params, its own controller context and its own `FOR_EVENT` DI scope (released when
622
+ * the handler settles). Status, headers and cookies it sets go to a detached response and
623
+ * are discarded.
624
+ *
625
+ * Use it to delegate work to another controller's route without a network round-trip or
626
+ * re-sending credentials. Rejects with `HttpError(404)` when no route matches.
627
+ *
628
+ * @example
629
+ * ```ts
630
+ * const http = await useControllerContext().instantiate(MoostHttp)
631
+ * const summary = await http.invoke('POST', '/issues/actions/close', { body: { ids } })
632
+ * ```
633
+ */ invoke(method, path, opts) {
634
+ const parent = current$1();
635
+ const caller = parent.has(httpKind$1.keys.response) ? parent.get(httpKind$1.keys.response) : void 0;
636
+ if (!caller) throw new Error("MoostHttp.invoke() must be called inside an HTTP event");
637
+ const child = forkEventContext({
638
+ parent,
639
+ isolate: opts?.isolate
640
+ });
641
+ child.setOwn(invocationKey, true);
642
+ const ResponseCtor = caller.constructor;
643
+ child.setOwn(httpKind$1.keys.response, new ResponseCtor(caller.getRawRes(true), parent.get(httpKind$1.keys.req), parent.logger, void 0, true));
644
+ seedBody(child, opts?.body, {
645
+ raw: opts?.rawBody,
646
+ contentType: opts?.contentType
647
+ });
648
+ opts?.prepare?.(child);
649
+ return run(child, async () => {
650
+ const handlers = this.httpApp.getWooks().lookupHandlers(method, path, child);
651
+ if (!handlers?.length) throw new HttpError$1(404, `No route for ${method} ${path}`);
652
+ let failure;
653
+ for (const handler of handlers) {
654
+ let result;
655
+ try {
656
+ result = await handler();
657
+ } catch (error) {
658
+ failure = error;
659
+ continue;
660
+ }
661
+ if (result instanceof Error) throw result;
662
+ return result;
663
+ }
664
+ throw failure;
665
+ });
666
+ }
607
667
  listen(port, hostname, backlog, listeningListener) {
608
668
  return this.httpApp.listen(port, hostname, backlog, listeningListener);
609
669
  }
@@ -693,7 +753,7 @@ const LOGGER_TITLE = "moost-http";
693
753
  image: "https://moost.org/moost-full-logo.svg",
694
754
  link: "https://moost.org/",
695
755
  poweredBy: "moostjs",
696
- version: "0.6.42"
756
+ version: "0.6.44"
697
757
  });
698
758
  if (httpApp && httpApp instanceof WooksHttp) this.httpApp = httpApp;
699
759
  else if (httpApp) this.httpApp = createHttpApp({
@@ -703,6 +763,7 @@ const LOGGER_TITLE = "moost-http";
703
763
  else this.httpApp = createHttpApp({ onNotFound: this.onNotFound.bind(this) });
704
764
  }
705
765
  };
766
+ /** Names this adapter for DI independently of class identity (see `MOOST_ADAPTER_BRAND`). */ _define_property(MoostHttp, MOOST_ADAPTER_BRAND, "@moostjs/event-http/MoostHttp");
706
767
 
707
768
  //#endregion
708
769
  //#region packages/event-http/src/local-fetch.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moostjs/event-http",
3
- "version": "0.6.42",
3
+ "version": "0.6.44",
4
4
  "description": "@moostjs/event-http",
5
5
  "keywords": [
6
6
  "composables",
@@ -38,16 +38,16 @@
38
38
  }
39
39
  },
40
40
  "dependencies": {
41
- "@wooksjs/event-http": "^0.7.25",
42
- "@wooksjs/http-body": "^0.7.25"
41
+ "@wooksjs/event-http": "^0.7.26",
42
+ "@wooksjs/http-body": "^0.7.26"
43
43
  },
44
44
  "devDependencies": {
45
45
  "vitest": "3.2.7"
46
46
  },
47
47
  "peerDependencies": {
48
48
  "@prostojs/infact": "^0.6.0",
49
- "@wooksjs/event-core": "^0.7.25",
50
- "moost": "^0.6.42"
49
+ "@wooksjs/event-core": "^0.7.26",
50
+ "moost": "^0.6.44"
51
51
  },
52
52
  "scripts": {
53
53
  "pub": "pnpm publish --access public",