@wooksjs/event-http 0.7.19 → 0.7.20

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
@@ -876,6 +876,21 @@ var HttpResponse = class {
876
876
  this._hasCookies = true;
877
877
  return this;
878
878
  }
879
+ /**
880
+ * Renders all buffered cookies (named via `setCookie()`, then raw via `setCookieRaw()`)
881
+ * as `Set-Cookie` header strings, without responding.
882
+ *
883
+ * Non-destructive: the buffers stay intact, so a later `send()` still emits the same
884
+ * cookies — callers that drain cookies onto the wire themselves should not also send
885
+ * through this wrapper. Cookies placed directly into headers (via `setHeader('set-cookie', …)`
886
+ * or default headers) are not included.
887
+ */
888
+ getSetCookieStrings() {
889
+ const rendered = [];
890
+ for (const [name, data] of Object.entries(this._cookies)) if (data) rendered.push(renderCookie(name, data));
891
+ rendered.push(...this._rawCookies);
892
+ return rendered;
893
+ }
879
894
  /** Sets the `Cache-Control` header from a directive object (chainable). */
880
895
  setCacheControl(data) {
881
896
  this._headers["cache-control"] = renderCacheControl(data);
@@ -1013,10 +1028,7 @@ var HttpResponse = class {
1013
1028
  }
1014
1029
  finalizeCookies() {
1015
1030
  if (!this._hasCookies) return;
1016
- const entries = Object.entries(this._cookies);
1017
- const rendered = [];
1018
- for (const [name, data] of entries) if (data) rendered.push(renderCookie(name, data));
1019
- if (this._rawCookies.length > 0) rendered.push(...this._rawCookies);
1031
+ const rendered = this.getSetCookieStrings();
1020
1032
  if (rendered.length > 0) {
1021
1033
  const existing = this._headers["set-cookie"];
1022
1034
  if (existing) this._headers["set-cookie"] = [...Array.isArray(existing) ? existing : [existing], ...rendered];
@@ -1457,7 +1469,7 @@ function escapeHtml(value) {
1457
1469
  //#endregion
1458
1470
  //#region packages/event-http/src/response/wooks-http-response.ts
1459
1471
  let framework = {
1460
- version: "0.7.18",
1472
+ version: "0.7.19",
1461
1473
  poweredBy: "wooksjs",
1462
1474
  link: "https://wooks.moost.org/",
1463
1475
  image: "https://wooks.moost.org/wooks-full-logo.svg"
@@ -1528,13 +1540,22 @@ function renderErrorText(data) {
1528
1540
 
1529
1541
  //#endregion
1530
1542
  //#region packages/event-http/src/http-adapter.ts
1531
- const DEFAULT_FORWARD_HEADERS = [
1543
+ /**
1544
+ * Identity headers forwarded from the calling HTTP context during programmatic `fetch()`
1545
+ * when no `forwardHeaders` option is configured.
1546
+ *
1547
+ * The `forwardHeaders` option REPLACES this list. To extend it instead, spread the constant:
1548
+ * ```ts
1549
+ * createHttpApp({ forwardHeaders: [...DEFAULT_FORWARD_HEADERS, 'cloudfront-viewer-address'] })
1550
+ * ```
1551
+ */
1552
+ const DEFAULT_FORWARD_HEADERS = Object.freeze([
1532
1553
  "authorization",
1533
1554
  "cookie",
1534
1555
  "accept-language",
1535
1556
  "x-forwarded-for",
1536
1557
  "x-request-id"
1537
- ];
1558
+ ]);
1538
1559
  /** HTTP adapter for Wooks that provides route registration, server lifecycle, and request handling. */
1539
1560
  var WooksHttp = class extends wooks.WooksAdapterBase {
1540
1561
  constructor(opts, wooks$1) {
@@ -1902,6 +1923,37 @@ var WooksHttp = class extends wooks.WooksAdapterBase {
1902
1923
  const req = input instanceof Request ? input : new Request(input, init);
1903
1924
  return this.fetch(req);
1904
1925
  }
1926
+ /**
1927
+ * Runs `fn` inside an HTTP event context seeded from a real `(req, res)` pair,
1928
+ * WITHOUT route dispatch. Composables that read request state (`useRequest`,
1929
+ * `useHeaders`, `useCookies`, `useAuthorization`) work; route-scoped state is empty.
1930
+ * Nested `fetch()` calls made during `fn` see this context as their caller,
1931
+ * so `forwardHeaders` and parent `Set-Cookie` propagation apply.
1932
+ *
1933
+ * Never writes to `res` — the caller owns the wire. The response wrapper is
1934
+ * created in capture mode, so even a stray `response.send()` inside `fn` only
1935
+ * finalizes state without touching the socket. Buffered response state
1936
+ * (e.g. `Set-Cookie` collected from nested fetches) can be applied by the
1937
+ * caller via the returned wrapper:
1938
+ * ```ts
1939
+ * const { result: html, response } = await http.withHttpContext(req, res, () => render(url))
1940
+ * for (const cookie of response.getSetCookieStrings()) {
1941
+ * res.appendHeader('Set-Cookie', cookie)
1942
+ * }
1943
+ * ```
1944
+ */
1945
+ async withHttpContext(req, res, fn) {
1946
+ const ctxOptions = this.eventContextOptions;
1947
+ const response = new this.ResponseClass(res, req, ctxOptions.logger, this.opts?.defaultHeaders, true);
1948
+ return {
1949
+ result: await createHttpContext(ctxOptions, {
1950
+ req,
1951
+ response,
1952
+ requestLimits: this.opts?.requestLimits
1953
+ }, fn),
1954
+ response
1955
+ };
1956
+ }
1905
1957
  };
1906
1958
  var NoopSocket = class extends stream.Duplex {
1907
1959
  constructor(..._args) {
@@ -2039,6 +2091,7 @@ function prepareTestHttpContext(options) {
2039
2091
  }
2040
2092
 
2041
2093
  //#endregion
2094
+ exports.DEFAULT_FORWARD_HEADERS = DEFAULT_FORWARD_HEADERS;
2042
2095
  exports.DEFAULT_LIMITS = DEFAULT_LIMITS;
2043
2096
  exports.EHttpStatusCode = EHttpStatusCode;
2044
2097
  exports.HttpError = HttpError;
package/dist/index.d.ts CHANGED
@@ -395,6 +395,16 @@ declare class HttpResponse {
395
395
  clearCookies(): this;
396
396
  /** Appends a raw `Set-Cookie` header string (chainable). Use when you need full control over the cookie format. */
397
397
  setCookieRaw(rawValue: string): this;
398
+ /**
399
+ * Renders all buffered cookies (named via `setCookie()`, then raw via `setCookieRaw()`)
400
+ * as `Set-Cookie` header strings, without responding.
401
+ *
402
+ * Non-destructive: the buffers stay intact, so a later `send()` still emits the same
403
+ * cookies — callers that drain cookies onto the wire themselves should not also send
404
+ * through this wrapper. Cookies placed directly into headers (via `setHeader('set-cookie', …)`
405
+ * or default headers) are not included.
406
+ */
407
+ getSetCookieStrings(): string[];
398
408
  /** Sets the `Cache-Control` header from a directive object (chainable). */
399
409
  setCacheControl(data: TCacheControl): this;
400
410
  /** Sets the `Age` header in seconds (chainable). Accepts a number or time string (e.g. `'2h 15m'`). */
@@ -509,6 +519,16 @@ declare class WooksHttpResponse extends HttpResponse {
509
519
  protected renderError(data: TWooksErrorBodyExt, ctx: EventContext): void;
510
520
  }
511
521
 
522
+ /**
523
+ * Identity headers forwarded from the calling HTTP context during programmatic `fetch()`
524
+ * when no `forwardHeaders` option is configured.
525
+ *
526
+ * The `forwardHeaders` option REPLACES this list. To extend it instead, spread the constant:
527
+ * ```ts
528
+ * createHttpApp({ forwardHeaders: [...DEFAULT_FORWARD_HEADERS, 'cloudfront-viewer-address'] })
529
+ * ```
530
+ */
531
+ declare const DEFAULT_FORWARD_HEADERS: readonly string[];
512
532
  /** Configuration options for the WooksHttp adapter. */
513
533
  interface TWooksHttpOptions {
514
534
  logger?: TConsoleBase;
@@ -522,8 +542,10 @@ interface TWooksHttpOptions {
522
542
  defaultHeaders?: Record<string, string | string[]>;
523
543
  /**
524
544
  * Headers forwarded from the calling HTTP context during programmatic `fetch()`.
545
+ * REPLACES the default list entirely — to add headers while keeping the defaults,
546
+ * spread the exported constant: `[...DEFAULT_FORWARD_HEADERS, 'my-header']`.
525
547
  * Set to `false` to disable forwarding entirely.
526
- * @default ['authorization', 'cookie', 'accept-language', 'x-forwarded-for', 'x-request-id']
548
+ * @default DEFAULT_FORWARD_HEADERS — ['authorization', 'cookie', 'accept-language', 'x-forwarded-for', 'x-request-id']
527
549
  */
528
550
  forwardHeaders?: string[] | false;
529
551
  }
@@ -637,6 +659,29 @@ declare class WooksHttp extends WooksAdapterBase {
637
659
  * @returns A Web Standard Response.
638
660
  */
639
661
  request(input: string | URL | Request, init?: RequestInit): Promise<Response | null>;
662
+ /**
663
+ * Runs `fn` inside an HTTP event context seeded from a real `(req, res)` pair,
664
+ * WITHOUT route dispatch. Composables that read request state (`useRequest`,
665
+ * `useHeaders`, `useCookies`, `useAuthorization`) work; route-scoped state is empty.
666
+ * Nested `fetch()` calls made during `fn` see this context as their caller,
667
+ * so `forwardHeaders` and parent `Set-Cookie` propagation apply.
668
+ *
669
+ * Never writes to `res` — the caller owns the wire. The response wrapper is
670
+ * created in capture mode, so even a stray `response.send()` inside `fn` only
671
+ * finalizes state without touching the socket. Buffered response state
672
+ * (e.g. `Set-Cookie` collected from nested fetches) can be applied by the
673
+ * caller via the returned wrapper:
674
+ * ```ts
675
+ * const { result: html, response } = await http.withHttpContext(req, res, () => render(url))
676
+ * for (const cookie of response.getSetCookieStrings()) {
677
+ * res.appendHeader('Set-Cookie', cookie)
678
+ * }
679
+ * ```
680
+ */
681
+ withHttpContext<T>(req: IncomingMessage, res: ServerResponse, fn: () => T): Promise<{
682
+ result: Awaited<T>;
683
+ response: HttpResponse;
684
+ }>;
640
685
  }
641
686
  /**
642
687
  * Creates a new WooksHttp application instance.
@@ -713,5 +758,5 @@ interface TTestHttpContext {
713
758
  */
714
759
  declare function prepareTestHttpContext(options: TTestHttpContext): <T>(cb: (...a: any[]) => T) => T;
715
760
 
716
- export { DEFAULT_LIMITS, EHttpStatusCode, HttpError, HttpResponse, WooksHttp, WooksHttpResponse, WooksURLSearchParams, createHttpApp, createHttpContext, httpKind, httpStatusCodes, prepareTestHttpContext, rawBodySlot, recordToWebHeaders, renderCacheControl, securityHeaders, useAccept, useAuthorization, useCookies, useHeaders, useHttpContext, useRequest, useResponse, useUrlParams };
761
+ export { DEFAULT_FORWARD_HEADERS, DEFAULT_LIMITS, EHttpStatusCode, HttpError, HttpResponse, WooksHttp, WooksHttpResponse, WooksURLSearchParams, createHttpApp, createHttpContext, httpKind, httpStatusCodes, prepareTestHttpContext, rawBodySlot, recordToWebHeaders, renderCacheControl, securityHeaders, useAccept, useAuthorization, useCookies, useHeaders, useHttpContext, useRequest, useResponse, useUrlParams };
717
762
  export type { KnownAcceptType, KnownAuthType, SecurityHeadersOptions, TCacheControl, TCookieAttributes, TCookieAttributesInput, THttpEventData, TRequestLimits, TSetCookieData, TTestHttpContext, TWooksErrorBody, TWooksErrorBodyExt, TWooksHttpOptions };
package/dist/index.mjs CHANGED
@@ -847,6 +847,21 @@ var HttpResponse = class {
847
847
  this._hasCookies = true;
848
848
  return this;
849
849
  }
850
+ /**
851
+ * Renders all buffered cookies (named via `setCookie()`, then raw via `setCookieRaw()`)
852
+ * as `Set-Cookie` header strings, without responding.
853
+ *
854
+ * Non-destructive: the buffers stay intact, so a later `send()` still emits the same
855
+ * cookies — callers that drain cookies onto the wire themselves should not also send
856
+ * through this wrapper. Cookies placed directly into headers (via `setHeader('set-cookie', …)`
857
+ * or default headers) are not included.
858
+ */
859
+ getSetCookieStrings() {
860
+ const rendered = [];
861
+ for (const [name, data] of Object.entries(this._cookies)) if (data) rendered.push(renderCookie(name, data));
862
+ rendered.push(...this._rawCookies);
863
+ return rendered;
864
+ }
850
865
  /** Sets the `Cache-Control` header from a directive object (chainable). */
851
866
  setCacheControl(data) {
852
867
  this._headers["cache-control"] = renderCacheControl(data);
@@ -984,10 +999,7 @@ var HttpResponse = class {
984
999
  }
985
1000
  finalizeCookies() {
986
1001
  if (!this._hasCookies) return;
987
- const entries = Object.entries(this._cookies);
988
- const rendered = [];
989
- for (const [name, data] of entries) if (data) rendered.push(renderCookie(name, data));
990
- if (this._rawCookies.length > 0) rendered.push(...this._rawCookies);
1002
+ const rendered = this.getSetCookieStrings();
991
1003
  if (rendered.length > 0) {
992
1004
  const existing = this._headers["set-cookie"];
993
1005
  if (existing) this._headers["set-cookie"] = [...Array.isArray(existing) ? existing : [existing], ...rendered];
@@ -1428,7 +1440,7 @@ function escapeHtml(value) {
1428
1440
  //#endregion
1429
1441
  //#region packages/event-http/src/response/wooks-http-response.ts
1430
1442
  let framework = {
1431
- version: "0.7.18",
1443
+ version: "0.7.19",
1432
1444
  poweredBy: "wooksjs",
1433
1445
  link: "https://wooks.moost.org/",
1434
1446
  image: "https://wooks.moost.org/wooks-full-logo.svg"
@@ -1499,13 +1511,22 @@ function renderErrorText(data) {
1499
1511
 
1500
1512
  //#endregion
1501
1513
  //#region packages/event-http/src/http-adapter.ts
1502
- const DEFAULT_FORWARD_HEADERS = [
1514
+ /**
1515
+ * Identity headers forwarded from the calling HTTP context during programmatic `fetch()`
1516
+ * when no `forwardHeaders` option is configured.
1517
+ *
1518
+ * The `forwardHeaders` option REPLACES this list. To extend it instead, spread the constant:
1519
+ * ```ts
1520
+ * createHttpApp({ forwardHeaders: [...DEFAULT_FORWARD_HEADERS, 'cloudfront-viewer-address'] })
1521
+ * ```
1522
+ */
1523
+ const DEFAULT_FORWARD_HEADERS = Object.freeze([
1503
1524
  "authorization",
1504
1525
  "cookie",
1505
1526
  "accept-language",
1506
1527
  "x-forwarded-for",
1507
1528
  "x-request-id"
1508
- ];
1529
+ ]);
1509
1530
  /** HTTP adapter for Wooks that provides route registration, server lifecycle, and request handling. */
1510
1531
  var WooksHttp = class extends WooksAdapterBase {
1511
1532
  constructor(opts, wooks) {
@@ -1873,6 +1894,37 @@ var WooksHttp = class extends WooksAdapterBase {
1873
1894
  const req = input instanceof Request ? input : new Request(input, init);
1874
1895
  return this.fetch(req);
1875
1896
  }
1897
+ /**
1898
+ * Runs `fn` inside an HTTP event context seeded from a real `(req, res)` pair,
1899
+ * WITHOUT route dispatch. Composables that read request state (`useRequest`,
1900
+ * `useHeaders`, `useCookies`, `useAuthorization`) work; route-scoped state is empty.
1901
+ * Nested `fetch()` calls made during `fn` see this context as their caller,
1902
+ * so `forwardHeaders` and parent `Set-Cookie` propagation apply.
1903
+ *
1904
+ * Never writes to `res` — the caller owns the wire. The response wrapper is
1905
+ * created in capture mode, so even a stray `response.send()` inside `fn` only
1906
+ * finalizes state without touching the socket. Buffered response state
1907
+ * (e.g. `Set-Cookie` collected from nested fetches) can be applied by the
1908
+ * caller via the returned wrapper:
1909
+ * ```ts
1910
+ * const { result: html, response } = await http.withHttpContext(req, res, () => render(url))
1911
+ * for (const cookie of response.getSetCookieStrings()) {
1912
+ * res.appendHeader('Set-Cookie', cookie)
1913
+ * }
1914
+ * ```
1915
+ */
1916
+ async withHttpContext(req, res, fn) {
1917
+ const ctxOptions = this.eventContextOptions;
1918
+ const response = new this.ResponseClass(res, req, ctxOptions.logger, this.opts?.defaultHeaders, true);
1919
+ return {
1920
+ result: await createHttpContext(ctxOptions, {
1921
+ req,
1922
+ response,
1923
+ requestLimits: this.opts?.requestLimits
1924
+ }, fn),
1925
+ response
1926
+ };
1927
+ }
1876
1928
  };
1877
1929
  var NoopSocket = class extends Duplex {
1878
1930
  constructor(..._args) {
@@ -2010,4 +2062,4 @@ function prepareTestHttpContext(options) {
2010
2062
  }
2011
2063
 
2012
2064
  //#endregion
2013
- export { DEFAULT_LIMITS, EHttpStatusCode, HttpError, HttpResponse, WooksHttp, WooksHttpResponse, WooksURLSearchParams, createHttpApp, createHttpContext, httpKind, httpStatusCodes, prepareTestHttpContext, rawBodySlot, recordToWebHeaders, renderCacheControl, securityHeaders, useAccept, useAuthorization, useCookies, useHeaders, useHttpContext, useLogger, useRequest, useResponse, useRouteParams, useUrlParams };
2065
+ export { DEFAULT_FORWARD_HEADERS, DEFAULT_LIMITS, EHttpStatusCode, HttpError, HttpResponse, WooksHttp, WooksHttpResponse, WooksURLSearchParams, createHttpApp, createHttpContext, httpKind, httpStatusCodes, prepareTestHttpContext, rawBodySlot, recordToWebHeaders, renderCacheControl, securityHeaders, useAccept, useAuthorization, useCookies, useHeaders, useHttpContext, useLogger, useRequest, useResponse, useRouteParams, useUrlParams };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wooksjs/event-http",
3
- "version": "0.7.19",
3
+ "version": "0.7.20",
4
4
  "description": "@wooksjs/event-http",
5
5
  "keywords": [
6
6
  "api",
@@ -42,14 +42,14 @@
42
42
  "devDependencies": {
43
43
  "typescript": "^5.9.3",
44
44
  "vitest": "^3.2.4",
45
- "@wooksjs/event-core": "^0.7.19",
46
- "wooks": "^0.7.19"
45
+ "@wooksjs/event-core": "^0.7.20",
46
+ "wooks": "^0.7.20"
47
47
  },
48
48
  "peerDependencies": {
49
49
  "@prostojs/logger": "^0.4.3",
50
50
  "@prostojs/router": "^0.3.4",
51
- "@wooksjs/event-core": "^0.7.19",
52
- "wooks": "^0.7.19"
51
+ "@wooksjs/event-core": "^0.7.20",
52
+ "wooks": "^0.7.20"
53
53
  },
54
54
  "scripts": {
55
55
  "build": "rolldown -c ../../rolldown.config.mjs"