@wooksjs/event-http 0.7.0 → 0.7.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.
- package/dist/index.cjs +39 -42
- package/dist/index.d.ts +30 -30
- package/dist/index.mjs +40 -43
- package/package.json +5 -5
- package/skills/wooksjs-event-http/SKILL.md +2 -2
- package/skills/wooksjs-event-http/core.md +7 -7
- package/skills/wooksjs-event-http/request.md +33 -33
- package/skills/wooksjs-event-http/testing.md +2 -2
package/dist/index.cjs
CHANGED
|
@@ -80,12 +80,12 @@ const parseCookieValue = (0, __wooksjs_event_core.cachedBy)((name, ctx) => {
|
|
|
80
80
|
* Provides access to parsed request cookies.
|
|
81
81
|
* @example
|
|
82
82
|
* ```ts
|
|
83
|
-
* const { getCookie,
|
|
83
|
+
* const { getCookie, raw } = useCookies()
|
|
84
84
|
* const sessionId = getCookie('session_id')
|
|
85
85
|
* ```
|
|
86
86
|
*/
|
|
87
87
|
const useCookies = (0, __wooksjs_event_core.defineWook)((ctx) => ({
|
|
88
|
-
|
|
88
|
+
raw: ctx.get(httpKind.keys.req).headers.cookie,
|
|
89
89
|
getCookie: (name) => parseCookieValue(name, ctx)
|
|
90
90
|
}));
|
|
91
91
|
|
|
@@ -107,7 +107,7 @@ const useAccept = (0, __wooksjs_event_core.defineWook)((ctx) => {
|
|
|
107
107
|
const accept = ctx.get(httpKind.keys.req).headers.accept;
|
|
108
108
|
return {
|
|
109
109
|
accept,
|
|
110
|
-
|
|
110
|
+
has: (type) => acceptsMime(type, ctx)
|
|
111
111
|
};
|
|
112
112
|
});
|
|
113
113
|
|
|
@@ -152,17 +152,17 @@ const authIsSlot = (0, __wooksjs_event_core.cachedBy)((type, ctx) => {
|
|
|
152
152
|
* Provides parsed access to the Authorization header (type, credentials, Basic decoding).
|
|
153
153
|
* @example
|
|
154
154
|
* ```ts
|
|
155
|
-
* const {
|
|
156
|
-
* if (
|
|
155
|
+
* const { is, credentials, basicCredentials } = useAuthorization()
|
|
156
|
+
* if (is('bearer')) { const token = credentials() }
|
|
157
157
|
* ```
|
|
158
158
|
*/
|
|
159
159
|
const useAuthorization = (0, __wooksjs_event_core.defineWook)((ctx) => {
|
|
160
160
|
const authorization = ctx.get(httpKind.keys.req).headers.authorization;
|
|
161
161
|
return {
|
|
162
162
|
authorization,
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
163
|
+
type: () => ctx.get(authTypeSlot),
|
|
164
|
+
credentials: () => ctx.get(authCredentialsSlot),
|
|
165
|
+
is: (type) => authIsSlot(type, ctx),
|
|
166
166
|
basicCredentials: () => ctx.get(basicCredentialsSlot)
|
|
167
167
|
};
|
|
168
168
|
});
|
|
@@ -520,7 +520,7 @@ const ipListSlot = (0, __wooksjs_event_core.cached)((ctx) => {
|
|
|
520
520
|
* Provides access to the incoming HTTP request (method, url, headers, body, IP).
|
|
521
521
|
* @example
|
|
522
522
|
* ```ts
|
|
523
|
-
* const { method, url, rawBody, getIp } = useRequest()
|
|
523
|
+
* const { method, url, raw, rawBody, getIp } = useRequest()
|
|
524
524
|
* const body = await rawBody()
|
|
525
525
|
* ```
|
|
526
526
|
*/
|
|
@@ -551,7 +551,7 @@ const useRequest = (0, __wooksjs_event_core.defineWook)((ctx) => {
|
|
|
551
551
|
return ctx.get(remoteIpSlot);
|
|
552
552
|
}
|
|
553
553
|
return {
|
|
554
|
-
|
|
554
|
+
raw: req,
|
|
555
555
|
url: req.url,
|
|
556
556
|
method: req.method,
|
|
557
557
|
headers: req.headers,
|
|
@@ -647,14 +647,14 @@ const urlSearchParamsSlot = (0, __wooksjs_event_core.cached)((ctx) => new WooksU
|
|
|
647
647
|
* Provides access to URL search (query) parameters from the request.
|
|
648
648
|
* @example
|
|
649
649
|
* ```ts
|
|
650
|
-
* const {
|
|
651
|
-
* const page =
|
|
650
|
+
* const { params, toJson } = useUrlParams()
|
|
651
|
+
* const page = params().get('page')
|
|
652
652
|
* ```
|
|
653
653
|
*/
|
|
654
|
-
const
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
654
|
+
const useUrlParams = (0, __wooksjs_event_core.defineWook)((ctx) => ({
|
|
655
|
+
raw: () => ctx.get(rawSearchParamsSlot),
|
|
656
|
+
params: () => ctx.get(urlSearchParamsSlot),
|
|
657
|
+
toJson: () => ctx.get(urlSearchParamsSlot).toJson()
|
|
658
658
|
}));
|
|
659
659
|
|
|
660
660
|
//#endregion
|
|
@@ -1028,13 +1028,12 @@ var HttpResponse = class {
|
|
|
1028
1028
|
//#region packages/event-http/src/event-http.ts
|
|
1029
1029
|
/** Creates an async event context for an incoming HTTP request/response pair. */
|
|
1030
1030
|
function createHttpContext(data, options, ResponseClass = HttpResponse) {
|
|
1031
|
-
const
|
|
1032
|
-
|
|
1033
|
-
return (fn) => (0, __wooksjs_event_core.run)(ctx, () => ctx.seed(httpKind, {
|
|
1031
|
+
const response = new ResponseClass(data.res, data.req, options.logger);
|
|
1032
|
+
return (fn) => (0, __wooksjs_event_core.createEventContext)(options, httpKind, {
|
|
1034
1033
|
req: data.req,
|
|
1035
1034
|
response,
|
|
1036
1035
|
requestLimits: data.requestLimits
|
|
1037
|
-
}, fn)
|
|
1036
|
+
}, fn);
|
|
1038
1037
|
}
|
|
1039
1038
|
/** Returns the current HTTP event context. */
|
|
1040
1039
|
function useHttpContext(ctx) {
|
|
@@ -1394,10 +1393,10 @@ function error_tl_default(ctx) {
|
|
|
1394
1393
|
//#endregion
|
|
1395
1394
|
//#region packages/event-http/src/response/wooks-http-response.ts
|
|
1396
1395
|
let framework = {
|
|
1397
|
-
version: "0.
|
|
1396
|
+
version: "0.7.1",
|
|
1398
1397
|
poweredBy: "wooksjs",
|
|
1399
1398
|
link: "https://wooks.moost.org/",
|
|
1400
|
-
image: "https://wooks.moost.org/wooks-full-logo.
|
|
1399
|
+
image: "https://wooks.moost.org/wooks-full-logo.svg"
|
|
1401
1400
|
};
|
|
1402
1401
|
const icons = {
|
|
1403
1402
|
401: typeof _403_tl_default === "function" ? _403_tl_default({}) : "",
|
|
@@ -1418,14 +1417,14 @@ var WooksHttpResponse = class extends HttpResponse {
|
|
|
1418
1417
|
}
|
|
1419
1418
|
renderError(data, ctx) {
|
|
1420
1419
|
this._status = data.statusCode || 500;
|
|
1421
|
-
const {
|
|
1422
|
-
if (
|
|
1420
|
+
const { has } = useAccept(ctx);
|
|
1421
|
+
if (has("json")) {
|
|
1423
1422
|
this._headers["content-type"] = "application/json";
|
|
1424
1423
|
this._body = JSON.stringify(data);
|
|
1425
|
-
} else if (
|
|
1424
|
+
} else if (has("html")) {
|
|
1426
1425
|
this._headers["content-type"] = "text/html";
|
|
1427
1426
|
this._body = renderErrorHtml(data);
|
|
1428
|
-
} else if (
|
|
1427
|
+
} else if (has("text")) {
|
|
1429
1428
|
this._headers["content-type"] = "text/plain";
|
|
1430
1429
|
this._body = renderErrorText(data);
|
|
1431
1430
|
} else {
|
|
@@ -1601,16 +1600,15 @@ var WooksHttp = class extends wooks.WooksAdapterBase {
|
|
|
1601
1600
|
const notFoundHandler = this.opts?.onNotFound;
|
|
1602
1601
|
const defaultHeaders = this.opts?.defaultHeaders;
|
|
1603
1602
|
return (req, res) => {
|
|
1604
|
-
const
|
|
1605
|
-
const response = new this.ResponseClass(res, req, ctx.logger, defaultHeaders);
|
|
1603
|
+
const response = new this.ResponseClass(res, req, ctxOptions.logger, defaultHeaders);
|
|
1606
1604
|
const method = req.method || "";
|
|
1607
1605
|
const url$1 = req.url || "";
|
|
1608
|
-
(0, __wooksjs_event_core.
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1606
|
+
(0, __wooksjs_event_core.createEventContext)(ctxOptions, httpKind, {
|
|
1607
|
+
req,
|
|
1608
|
+
response,
|
|
1609
|
+
requestLimits: RequestLimits
|
|
1610
|
+
}, () => {
|
|
1611
|
+
const ctx = (0, __wooksjs_event_core.current)();
|
|
1614
1612
|
const handlers = this.wooks.lookupHandlers(method, url$1, ctx);
|
|
1615
1613
|
if (handlers || notFoundHandler) {
|
|
1616
1614
|
const result = this.processHandlers(handlers || [notFoundHandler], ctx, response);
|
|
@@ -1639,14 +1637,13 @@ var WooksHttp = class extends wooks.WooksAdapterBase {
|
|
|
1639
1637
|
socket.destroy();
|
|
1640
1638
|
return;
|
|
1641
1639
|
}
|
|
1642
|
-
const ctx = new __wooksjs_event_core.EventContext(ctxOptions);
|
|
1643
1640
|
const url$1 = req.url || "";
|
|
1644
|
-
(0, __wooksjs_event_core.
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1641
|
+
(0, __wooksjs_event_core.createEventContext)(ctxOptions, httpKind, {
|
|
1642
|
+
req,
|
|
1643
|
+
response: void 0,
|
|
1644
|
+
requestLimits
|
|
1645
|
+
}, () => {
|
|
1646
|
+
const ctx = (0, __wooksjs_event_core.current)();
|
|
1650
1647
|
ctx.set(wsHandler.reqKey, req);
|
|
1651
1648
|
ctx.set(wsHandler.socketKey, socket);
|
|
1652
1649
|
ctx.set(wsHandler.headKey, head);
|
|
@@ -1871,4 +1868,4 @@ Object.defineProperty(exports, 'useRouteParams', {
|
|
|
1871
1868
|
return __wooksjs_event_core.useRouteParams;
|
|
1872
1869
|
}
|
|
1873
1870
|
});
|
|
1874
|
-
exports.
|
|
1871
|
+
exports.useUrlParams = useUrlParams;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as _wooksjs_event_core from '@wooksjs/event-core';
|
|
2
|
-
import { EventContext, Logger, EventContextOptions } from '@wooksjs/event-core';
|
|
2
|
+
import { EventContext as EventContext$1, Logger, EventContextOptions } from '@wooksjs/event-core';
|
|
3
3
|
export { EventContext, EventContextOptions, useLogger, useRouteParams } from '@wooksjs/event-core';
|
|
4
4
|
import * as http from 'http';
|
|
5
5
|
import { IncomingHttpHeaders, IncomingMessage, ServerResponse, Server } from 'http';
|
|
@@ -15,21 +15,21 @@ import { Duplex } from 'stream';
|
|
|
15
15
|
* Provides access to parsed request cookies.
|
|
16
16
|
* @example
|
|
17
17
|
* ```ts
|
|
18
|
-
* const { getCookie,
|
|
18
|
+
* const { getCookie, raw } = useCookies()
|
|
19
19
|
* const sessionId = getCookie('session_id')
|
|
20
20
|
* ```
|
|
21
21
|
*/
|
|
22
|
-
declare const useCookies: (ctx?: EventContext) => {
|
|
23
|
-
|
|
22
|
+
declare const useCookies: (ctx?: EventContext$1) => {
|
|
23
|
+
raw: string | undefined;
|
|
24
24
|
getCookie: (name: string) => string | null;
|
|
25
25
|
};
|
|
26
26
|
|
|
27
27
|
/** Short names for common Accept MIME types. */
|
|
28
28
|
type KnownAcceptType = 'json' | 'html' | 'xml' | 'text';
|
|
29
29
|
/** Provides helpers to check the request's Accept header for supported MIME types. */
|
|
30
|
-
declare const useAccept: (ctx?: EventContext) => {
|
|
30
|
+
declare const useAccept: (ctx?: EventContext$1) => {
|
|
31
31
|
accept: string | undefined;
|
|
32
|
-
|
|
32
|
+
has: (type: KnownAcceptType | (string & {})) => boolean;
|
|
33
33
|
};
|
|
34
34
|
|
|
35
35
|
/** Short names for common Authorization schemes. */
|
|
@@ -38,15 +38,15 @@ type KnownAuthType = 'basic' | 'bearer';
|
|
|
38
38
|
* Provides parsed access to the Authorization header (type, credentials, Basic decoding).
|
|
39
39
|
* @example
|
|
40
40
|
* ```ts
|
|
41
|
-
* const {
|
|
42
|
-
* if (
|
|
41
|
+
* const { is, credentials, basicCredentials } = useAuthorization()
|
|
42
|
+
* if (is('bearer')) { const token = credentials() }
|
|
43
43
|
* ```
|
|
44
44
|
*/
|
|
45
|
-
declare const useAuthorization: (ctx?: EventContext) => {
|
|
45
|
+
declare const useAuthorization: (ctx?: EventContext$1) => {
|
|
46
46
|
authorization: string | undefined;
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
47
|
+
type: () => string | null;
|
|
48
|
+
credentials: () => string | null;
|
|
49
|
+
is: (type: KnownAuthType | (string & {})) => boolean;
|
|
50
50
|
basicCredentials: () => {
|
|
51
51
|
username: string;
|
|
52
52
|
password: string;
|
|
@@ -60,7 +60,7 @@ declare const useAuthorization: (ctx?: EventContext) => {
|
|
|
60
60
|
* const { host, authorization } = useHeaders()
|
|
61
61
|
* ```
|
|
62
62
|
*/
|
|
63
|
-
declare function useHeaders(ctx?: EventContext): IncomingHttpHeaders;
|
|
63
|
+
declare function useHeaders(ctx?: EventContext$1): IncomingHttpHeaders;
|
|
64
64
|
|
|
65
65
|
/** Default safety limits for request body reading (size, ratio, timeout). */
|
|
66
66
|
declare const DEFAULT_LIMITS: {
|
|
@@ -75,12 +75,12 @@ declare const rawBodySlot: _wooksjs_event_core.Cached<Promise<Buffer$1<ArrayBuff
|
|
|
75
75
|
* Provides access to the incoming HTTP request (method, url, headers, body, IP).
|
|
76
76
|
* @example
|
|
77
77
|
* ```ts
|
|
78
|
-
* const { method, url, rawBody, getIp } = useRequest()
|
|
78
|
+
* const { method, url, raw, rawBody, getIp } = useRequest()
|
|
79
79
|
* const body = await rawBody()
|
|
80
80
|
* ```
|
|
81
81
|
*/
|
|
82
|
-
declare const useRequest: (ctx?: EventContext) => {
|
|
83
|
-
|
|
82
|
+
declare const useRequest: (ctx?: EventContext$1) => {
|
|
83
|
+
raw: http.IncomingMessage;
|
|
84
84
|
url: string | undefined;
|
|
85
85
|
method: string | undefined;
|
|
86
86
|
headers: http.IncomingHttpHeaders;
|
|
@@ -410,9 +410,9 @@ declare class HttpResponse {
|
|
|
410
410
|
/** Whether the response has already been sent (or the underlying stream is no longer writable). */
|
|
411
411
|
get responded(): boolean;
|
|
412
412
|
protected renderBody(): string | Uint8Array;
|
|
413
|
-
protected renderError(data: TWooksErrorBodyExt, _ctx: EventContext): void;
|
|
413
|
+
protected renderError(data: TWooksErrorBodyExt, _ctx: EventContext$1): void;
|
|
414
414
|
/** Renders and sends an HTTP error response. Called automatically by the framework when a handler throws an `HttpError`. */
|
|
415
|
-
sendError(error: HttpError, ctx: EventContext): void | Promise<void>;
|
|
415
|
+
sendError(error: HttpError, ctx: EventContext$1): void | Promise<void>;
|
|
416
416
|
/**
|
|
417
417
|
* Finalizes and sends the response.
|
|
418
418
|
*
|
|
@@ -442,7 +442,7 @@ declare class HttpResponse {
|
|
|
442
442
|
* response.setCookie('session', 'abc', { httpOnly: true })
|
|
443
443
|
* ```
|
|
444
444
|
*/
|
|
445
|
-
declare function useResponse(ctx?: EventContext): HttpResponse;
|
|
445
|
+
declare function useResponse(ctx?: EventContext$1): HttpResponse;
|
|
446
446
|
|
|
447
447
|
/**
|
|
448
448
|
* Extended `URLSearchParams` with safe JSON conversion.
|
|
@@ -459,14 +459,14 @@ declare class WooksURLSearchParams extends URLSearchParams {
|
|
|
459
459
|
* Provides access to URL search (query) parameters from the request.
|
|
460
460
|
* @example
|
|
461
461
|
* ```ts
|
|
462
|
-
* const {
|
|
463
|
-
* const page =
|
|
462
|
+
* const { params, toJson } = useUrlParams()
|
|
463
|
+
* const page = params().get('page')
|
|
464
464
|
* ```
|
|
465
465
|
*/
|
|
466
|
-
declare const
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
466
|
+
declare const useUrlParams: (ctx?: EventContext$1) => {
|
|
467
|
+
raw: () => string;
|
|
468
|
+
params: () => WooksURLSearchParams;
|
|
469
|
+
toJson: () => unknown;
|
|
470
470
|
};
|
|
471
471
|
|
|
472
472
|
/** Creates an async event context for an incoming HTTP request/response pair. */
|
|
@@ -488,7 +488,7 @@ declare class WooksHttpResponse extends HttpResponse {
|
|
|
488
488
|
link: string;
|
|
489
489
|
image: string;
|
|
490
490
|
}): void;
|
|
491
|
-
protected renderError(data: TWooksErrorBodyExt, ctx: EventContext): void;
|
|
491
|
+
protected renderError(data: TWooksErrorBodyExt, ctx: EventContext$1): void;
|
|
492
492
|
}
|
|
493
493
|
|
|
494
494
|
/** Configuration options for the WooksHttp adapter. */
|
|
@@ -566,7 +566,7 @@ declare class WooksHttp extends WooksAdapterBase {
|
|
|
566
566
|
* @param server Server
|
|
567
567
|
*/
|
|
568
568
|
attachServer(server?: Server): void;
|
|
569
|
-
protected respond(data: unknown, response: HttpResponse, ctx: EventContext): void | Promise<void>;
|
|
569
|
+
protected respond(data: unknown, response: HttpResponse, ctx: EventContext$1): void | Promise<void>;
|
|
570
570
|
/**
|
|
571
571
|
* Returns server callback function
|
|
572
572
|
* that can be passed to any node server:
|
|
@@ -585,8 +585,8 @@ declare class WooksHttp extends WooksAdapterBase {
|
|
|
585
585
|
* Creates an HTTP context, seeds it with upgrade data, and routes as method 'UPGRADE'.
|
|
586
586
|
*/
|
|
587
587
|
getUpgradeCb(): (req: IncomingMessage, socket: Duplex, head: Buffer) => void;
|
|
588
|
-
protected processUpgradeHandlers(handlers: TWooksHandler[], ctx: EventContext, socket: Duplex): void | Promise<unknown>;
|
|
589
|
-
protected processHandlers(handlers: TWooksHandler[], ctx: EventContext, response: HttpResponse): void | Promise<unknown>;
|
|
588
|
+
protected processUpgradeHandlers(handlers: TWooksHandler[], ctx: EventContext$1, socket: Duplex): void | Promise<unknown>;
|
|
589
|
+
protected processHandlers(handlers: TWooksHandler[], ctx: EventContext$1, response: HttpResponse): void | Promise<unknown>;
|
|
590
590
|
private processAsyncResult;
|
|
591
591
|
}
|
|
592
592
|
/**
|
|
@@ -671,5 +671,5 @@ interface TTestHttpContext {
|
|
|
671
671
|
*/
|
|
672
672
|
declare function prepareTestHttpContext(options: TTestHttpContext): <T>(cb: (...a: any[]) => T) => T;
|
|
673
673
|
|
|
674
|
-
export { DEFAULT_LIMITS, EHttpStatusCode, HttpError, HttpResponse, WooksHttp, WooksHttpResponse, WooksURLSearchParams, createHttpApp, createHttpContext, httpKind, httpStatusCodes, prepareTestHttpContext, rawBodySlot, renderCacheControl, securityHeaders, useAccept, useAuthorization, useCookies, useHeaders, useHttpContext, useRequest, useResponse,
|
|
674
|
+
export { DEFAULT_LIMITS, EHttpStatusCode, HttpError, HttpResponse, WooksHttp, WooksHttpResponse, WooksURLSearchParams, createHttpApp, createHttpContext, httpKind, httpStatusCodes, prepareTestHttpContext, rawBodySlot, renderCacheControl, securityHeaders, useAccept, useAuthorization, useCookies, useHeaders, useHttpContext, useRequest, useResponse, useUrlParams };
|
|
675
675
|
export type { KnownAcceptType, KnownAuthType, SecurityHeadersOptions, TCacheControl, TCookieAttributes, TCookieAttributesInput, THttpEventData, TRequestLimits, TSetCookieData, TTestHttpContext, TWooksErrorBody, TWooksErrorBodyExt, TWooksHttpOptions };
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { EventContext, cached, cachedBy, current, defineEventKind, defineWook, routeParamsKey, run, slot, useEventId, useLogger, useRouteParams } from "@wooksjs/event-core";
|
|
1
|
+
import { EventContext, cached, cachedBy, createEventContext, current, defineEventKind, defineWook, routeParamsKey, run, slot, useEventId, useLogger, useRouteParams } from "@wooksjs/event-core";
|
|
2
2
|
import { Buffer as Buffer$1 } from "buffer";
|
|
3
3
|
import { Readable, pipeline } from "node:stream";
|
|
4
4
|
import { promisify } from "node:util";
|
|
@@ -57,12 +57,12 @@ const parseCookieValue = cachedBy((name, ctx) => {
|
|
|
57
57
|
* Provides access to parsed request cookies.
|
|
58
58
|
* @example
|
|
59
59
|
* ```ts
|
|
60
|
-
* const { getCookie,
|
|
60
|
+
* const { getCookie, raw } = useCookies()
|
|
61
61
|
* const sessionId = getCookie('session_id')
|
|
62
62
|
* ```
|
|
63
63
|
*/
|
|
64
64
|
const useCookies = defineWook((ctx) => ({
|
|
65
|
-
|
|
65
|
+
raw: ctx.get(httpKind.keys.req).headers.cookie,
|
|
66
66
|
getCookie: (name) => parseCookieValue(name, ctx)
|
|
67
67
|
}));
|
|
68
68
|
|
|
@@ -84,7 +84,7 @@ const useAccept = defineWook((ctx) => {
|
|
|
84
84
|
const accept = ctx.get(httpKind.keys.req).headers.accept;
|
|
85
85
|
return {
|
|
86
86
|
accept,
|
|
87
|
-
|
|
87
|
+
has: (type) => acceptsMime(type, ctx)
|
|
88
88
|
};
|
|
89
89
|
});
|
|
90
90
|
|
|
@@ -129,17 +129,17 @@ const authIsSlot = cachedBy((type, ctx) => {
|
|
|
129
129
|
* Provides parsed access to the Authorization header (type, credentials, Basic decoding).
|
|
130
130
|
* @example
|
|
131
131
|
* ```ts
|
|
132
|
-
* const {
|
|
133
|
-
* if (
|
|
132
|
+
* const { is, credentials, basicCredentials } = useAuthorization()
|
|
133
|
+
* if (is('bearer')) { const token = credentials() }
|
|
134
134
|
* ```
|
|
135
135
|
*/
|
|
136
136
|
const useAuthorization = defineWook((ctx) => {
|
|
137
137
|
const authorization = ctx.get(httpKind.keys.req).headers.authorization;
|
|
138
138
|
return {
|
|
139
139
|
authorization,
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
140
|
+
type: () => ctx.get(authTypeSlot),
|
|
141
|
+
credentials: () => ctx.get(authCredentialsSlot),
|
|
142
|
+
is: (type) => authIsSlot(type, ctx),
|
|
143
143
|
basicCredentials: () => ctx.get(basicCredentialsSlot)
|
|
144
144
|
};
|
|
145
145
|
});
|
|
@@ -497,7 +497,7 @@ const ipListSlot = cached((ctx) => {
|
|
|
497
497
|
* Provides access to the incoming HTTP request (method, url, headers, body, IP).
|
|
498
498
|
* @example
|
|
499
499
|
* ```ts
|
|
500
|
-
* const { method, url, rawBody, getIp } = useRequest()
|
|
500
|
+
* const { method, url, raw, rawBody, getIp } = useRequest()
|
|
501
501
|
* const body = await rawBody()
|
|
502
502
|
* ```
|
|
503
503
|
*/
|
|
@@ -528,7 +528,7 @@ const useRequest = defineWook((ctx) => {
|
|
|
528
528
|
return ctx.get(remoteIpSlot);
|
|
529
529
|
}
|
|
530
530
|
return {
|
|
531
|
-
|
|
531
|
+
raw: req,
|
|
532
532
|
url: req.url,
|
|
533
533
|
method: req.method,
|
|
534
534
|
headers: req.headers,
|
|
@@ -624,14 +624,14 @@ const urlSearchParamsSlot = cached((ctx) => new WooksURLSearchParams(ctx.get(raw
|
|
|
624
624
|
* Provides access to URL search (query) parameters from the request.
|
|
625
625
|
* @example
|
|
626
626
|
* ```ts
|
|
627
|
-
* const {
|
|
628
|
-
* const page =
|
|
627
|
+
* const { params, toJson } = useUrlParams()
|
|
628
|
+
* const page = params().get('page')
|
|
629
629
|
* ```
|
|
630
630
|
*/
|
|
631
|
-
const
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
631
|
+
const useUrlParams = defineWook((ctx) => ({
|
|
632
|
+
raw: () => ctx.get(rawSearchParamsSlot),
|
|
633
|
+
params: () => ctx.get(urlSearchParamsSlot),
|
|
634
|
+
toJson: () => ctx.get(urlSearchParamsSlot).toJson()
|
|
635
635
|
}));
|
|
636
636
|
|
|
637
637
|
//#endregion
|
|
@@ -1005,13 +1005,12 @@ var HttpResponse = class {
|
|
|
1005
1005
|
//#region packages/event-http/src/event-http.ts
|
|
1006
1006
|
/** Creates an async event context for an incoming HTTP request/response pair. */
|
|
1007
1007
|
function createHttpContext(data, options, ResponseClass = HttpResponse) {
|
|
1008
|
-
const
|
|
1009
|
-
|
|
1010
|
-
return (fn) => run(ctx, () => ctx.seed(httpKind, {
|
|
1008
|
+
const response = new ResponseClass(data.res, data.req, options.logger);
|
|
1009
|
+
return (fn) => createEventContext(options, httpKind, {
|
|
1011
1010
|
req: data.req,
|
|
1012
1011
|
response,
|
|
1013
1012
|
requestLimits: data.requestLimits
|
|
1014
|
-
}, fn)
|
|
1013
|
+
}, fn);
|
|
1015
1014
|
}
|
|
1016
1015
|
/** Returns the current HTTP event context. */
|
|
1017
1016
|
function useHttpContext(ctx) {
|
|
@@ -1371,10 +1370,10 @@ function error_tl_default(ctx) {
|
|
|
1371
1370
|
//#endregion
|
|
1372
1371
|
//#region packages/event-http/src/response/wooks-http-response.ts
|
|
1373
1372
|
let framework = {
|
|
1374
|
-
version: "0.
|
|
1373
|
+
version: "0.7.1",
|
|
1375
1374
|
poweredBy: "wooksjs",
|
|
1376
1375
|
link: "https://wooks.moost.org/",
|
|
1377
|
-
image: "https://wooks.moost.org/wooks-full-logo.
|
|
1376
|
+
image: "https://wooks.moost.org/wooks-full-logo.svg"
|
|
1378
1377
|
};
|
|
1379
1378
|
const icons = {
|
|
1380
1379
|
401: typeof _403_tl_default === "function" ? _403_tl_default({}) : "",
|
|
@@ -1395,14 +1394,14 @@ var WooksHttpResponse = class extends HttpResponse {
|
|
|
1395
1394
|
}
|
|
1396
1395
|
renderError(data, ctx) {
|
|
1397
1396
|
this._status = data.statusCode || 500;
|
|
1398
|
-
const {
|
|
1399
|
-
if (
|
|
1397
|
+
const { has } = useAccept(ctx);
|
|
1398
|
+
if (has("json")) {
|
|
1400
1399
|
this._headers["content-type"] = "application/json";
|
|
1401
1400
|
this._body = JSON.stringify(data);
|
|
1402
|
-
} else if (
|
|
1401
|
+
} else if (has("html")) {
|
|
1403
1402
|
this._headers["content-type"] = "text/html";
|
|
1404
1403
|
this._body = renderErrorHtml(data);
|
|
1405
|
-
} else if (
|
|
1404
|
+
} else if (has("text")) {
|
|
1406
1405
|
this._headers["content-type"] = "text/plain";
|
|
1407
1406
|
this._body = renderErrorText(data);
|
|
1408
1407
|
} else {
|
|
@@ -1578,16 +1577,15 @@ var WooksHttp = class extends WooksAdapterBase {
|
|
|
1578
1577
|
const notFoundHandler = this.opts?.onNotFound;
|
|
1579
1578
|
const defaultHeaders = this.opts?.defaultHeaders;
|
|
1580
1579
|
return (req, res) => {
|
|
1581
|
-
const
|
|
1582
|
-
const response = new this.ResponseClass(res, req, ctx.logger, defaultHeaders);
|
|
1580
|
+
const response = new this.ResponseClass(res, req, ctxOptions.logger, defaultHeaders);
|
|
1583
1581
|
const method = req.method || "";
|
|
1584
1582
|
const url = req.url || "";
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1583
|
+
createEventContext(ctxOptions, httpKind, {
|
|
1584
|
+
req,
|
|
1585
|
+
response,
|
|
1586
|
+
requestLimits: RequestLimits
|
|
1587
|
+
}, () => {
|
|
1588
|
+
const ctx = current();
|
|
1591
1589
|
const handlers = this.wooks.lookupHandlers(method, url, ctx);
|
|
1592
1590
|
if (handlers || notFoundHandler) {
|
|
1593
1591
|
const result = this.processHandlers(handlers || [notFoundHandler], ctx, response);
|
|
@@ -1616,14 +1614,13 @@ var WooksHttp = class extends WooksAdapterBase {
|
|
|
1616
1614
|
socket.destroy();
|
|
1617
1615
|
return;
|
|
1618
1616
|
}
|
|
1619
|
-
const ctx = new EventContext(ctxOptions);
|
|
1620
1617
|
const url = req.url || "";
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1618
|
+
createEventContext(ctxOptions, httpKind, {
|
|
1619
|
+
req,
|
|
1620
|
+
response: void 0,
|
|
1621
|
+
requestLimits
|
|
1622
|
+
}, () => {
|
|
1623
|
+
const ctx = current();
|
|
1627
1624
|
ctx.set(wsHandler.reqKey, req);
|
|
1628
1625
|
ctx.set(wsHandler.socketKey, socket);
|
|
1629
1626
|
ctx.set(wsHandler.headKey, head);
|
|
@@ -1814,4 +1811,4 @@ function prepareTestHttpContext(options) {
|
|
|
1814
1811
|
}
|
|
1815
1812
|
|
|
1816
1813
|
//#endregion
|
|
1817
|
-
export { DEFAULT_LIMITS, EHttpStatusCode, HttpError, HttpResponse, WooksHttp, WooksHttpResponse, WooksURLSearchParams, createHttpApp, createHttpContext, httpKind, httpStatusCodes, prepareTestHttpContext, rawBodySlot, renderCacheControl, securityHeaders, useAccept, useAuthorization, useCookies, useHeaders, useHttpContext, useLogger, useRequest, useResponse, useRouteParams,
|
|
1814
|
+
export { DEFAULT_LIMITS, EHttpStatusCode, HttpError, HttpResponse, WooksHttp, WooksHttpResponse, WooksURLSearchParams, createHttpApp, createHttpContext, httpKind, httpStatusCodes, prepareTestHttpContext, rawBodySlot, 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.
|
|
3
|
+
"version": "0.7.2",
|
|
4
4
|
"description": "@wooksjs/event-http",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"api",
|
|
@@ -47,14 +47,14 @@
|
|
|
47
47
|
"devDependencies": {
|
|
48
48
|
"typescript": "^5.9.3",
|
|
49
49
|
"vitest": "^3.2.4",
|
|
50
|
-
"@wooksjs/event-core": "^0.7.
|
|
51
|
-
"wooks": "^0.7.
|
|
50
|
+
"@wooksjs/event-core": "^0.7.2",
|
|
51
|
+
"wooks": "^0.7.2"
|
|
52
52
|
},
|
|
53
53
|
"peerDependencies": {
|
|
54
54
|
"@prostojs/logger": "^0.4.3",
|
|
55
55
|
"@prostojs/router": "^0.3.2",
|
|
56
|
-
"@wooksjs/event-core": "^0.7.
|
|
57
|
-
"wooks": "^0.7.
|
|
56
|
+
"@wooksjs/event-core": "^0.7.2",
|
|
57
|
+
"wooks": "^0.7.2"
|
|
58
58
|
},
|
|
59
59
|
"scripts": {
|
|
60
60
|
"build": "rolldown -c ../../rolldown.config.mjs",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: wooksjs-event-http
|
|
3
|
-
description: Use this skill when working with @wooksjs/event-http — to create HTTP servers with createHttpApp(), register route handlers with app.get()/post()/put()/patch()/delete(), read request data with useRequest()/useHeaders()/useCookies()/
|
|
3
|
+
description: Use this skill when working with @wooksjs/event-http — to create HTTP servers with createHttpApp(), register route handlers with app.get()/post()/put()/patch()/delete(), read request data with useRequest()/useHeaders()/useCookies()/useUrlParams()/useAuthorization()/useAccept(), control responses with useResponse() and HttpResponse (status, headers, cookies, cache control, streaming), throw HTTP errors with HttpError, test handlers with prepareTestHttpContext(), or integrate with existing Node.js servers via getServerCb().
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# @wooksjs/event-http
|
|
@@ -29,7 +29,7 @@ import {
|
|
|
29
29
|
useResponse,
|
|
30
30
|
useHeaders,
|
|
31
31
|
useCookies,
|
|
32
|
-
|
|
32
|
+
useUrlParams,
|
|
33
33
|
useAuthorization,
|
|
34
34
|
useAccept,
|
|
35
35
|
useRouteParams,
|
|
@@ -32,13 +32,13 @@ app.listen(3000)
|
|
|
32
32
|
|
|
33
33
|
**Options (`TWooksHttpOptions`):**
|
|
34
34
|
|
|
35
|
-
| Option
|
|
36
|
-
|
|
|
37
|
-
| `logger`
|
|
38
|
-
| `onNotFound`
|
|
39
|
-
| `router`
|
|
40
|
-
| `requestLimits`
|
|
41
|
-
| `responseClass`
|
|
35
|
+
| Option | Type | Description |
|
|
36
|
+
| ---------------- | ------------------------------------ | ------------------------------------------------------------------------- |
|
|
37
|
+
| `logger` | `TConsoleBase` | Custom logger instance |
|
|
38
|
+
| `onNotFound` | `TWooksHandler` | Handler called when no route matches (default: 404 HttpError) |
|
|
39
|
+
| `router` | router options | Custom router configuration |
|
|
40
|
+
| `requestLimits` | `Omit<TRequestLimits, 'perRequest'>` | Default body size/timeout limits for all requests |
|
|
41
|
+
| `responseClass` | `typeof WooksHttpResponse` | Custom response subclass (default: `WooksHttpResponse`) |
|
|
42
42
|
| `defaultHeaders` | `Record<string, string \| string[]>` | Default headers applied to every response (e.g. from `securityHeaders()`) |
|
|
43
43
|
|
|
44
44
|
### Route registration
|
|
@@ -22,17 +22,17 @@ const { method, url, headers, rawBody, getIp, reqId } = useRequest()
|
|
|
22
22
|
|
|
23
23
|
**Returned properties:**
|
|
24
24
|
|
|
25
|
-
| Property | Type
|
|
26
|
-
| ---------------- |
|
|
27
|
-
| `
|
|
28
|
-
| `url` | `string`
|
|
29
|
-
| `method` | `string`
|
|
30
|
-
| `headers` | `IncomingHttpHeaders`
|
|
31
|
-
| `rawBody` | `() => Promise<Buffer>`
|
|
32
|
-
| `reqId` | `() => string`
|
|
33
|
-
| `getIp(opts?)` | `(opts?: { trustProxy: boolean }) => string`
|
|
25
|
+
| Property | Type | Description |
|
|
26
|
+
| ---------------- | ------------------------------------------------- | -------------------------------------------------- |
|
|
27
|
+
| `raw` | `IncomingMessage` | Node.js raw request object |
|
|
28
|
+
| `url` | `string` | Request URL |
|
|
29
|
+
| `method` | `string` | HTTP method |
|
|
30
|
+
| `headers` | `IncomingHttpHeaders` | Request headers |
|
|
31
|
+
| `rawBody` | `() => Promise<Buffer>` | Lazy — reads and decompresses request body on call |
|
|
32
|
+
| `reqId` | `() => string` | Lazy UUID per request |
|
|
33
|
+
| `getIp(opts?)` | `(opts?: { trustProxy: boolean }) => string` | Client IP (with optional proxy trust) |
|
|
34
34
|
| `getIpList()` | `() => { remoteIp: string; forwarded: string[] }` | All IPs (remote + X-Forwarded-For) |
|
|
35
|
-
| `isCompressed()` | `() => boolean`
|
|
35
|
+
| `isCompressed()` | `() => boolean` | Whether the request body is compressed |
|
|
36
36
|
|
|
37
37
|
**Request limits (per-request override):**
|
|
38
38
|
|
|
@@ -61,30 +61,30 @@ Parses incoming request cookies lazily (per cookie name, via `cachedBy`).
|
|
|
61
61
|
```ts
|
|
62
62
|
import { useCookies } from '@wooksjs/event-http'
|
|
63
63
|
|
|
64
|
-
const { getCookie,
|
|
64
|
+
const { getCookie, raw } = useCookies()
|
|
65
65
|
const session = getCookie('session_id') // parsed + cached
|
|
66
66
|
const theme = getCookie('theme') // parsed + cached (different key)
|
|
67
|
-
|
|
67
|
+
// raw = raw Cookie header string
|
|
68
68
|
```
|
|
69
69
|
|
|
70
|
-
### `
|
|
70
|
+
### `useUrlParams(ctx?)`
|
|
71
71
|
|
|
72
72
|
Provides access to URL query parameters.
|
|
73
73
|
|
|
74
74
|
```ts
|
|
75
|
-
import {
|
|
75
|
+
import { useUrlParams } from '@wooksjs/event-http'
|
|
76
76
|
|
|
77
|
-
const {
|
|
77
|
+
const { params, toJson, raw } = useUrlParams()
|
|
78
78
|
|
|
79
79
|
// URLSearchParams API
|
|
80
|
-
const page =
|
|
81
|
-
const tags =
|
|
80
|
+
const page = params().get('page')
|
|
81
|
+
const tags = params().getAll('tag')
|
|
82
82
|
|
|
83
83
|
// As a plain object
|
|
84
|
-
const query =
|
|
84
|
+
const query = toJson() // { page: '1', tag: ['a', 'b'] }
|
|
85
85
|
|
|
86
86
|
// Raw query string
|
|
87
|
-
const
|
|
87
|
+
const rawQuery = raw() // '?page=1&tag=a&tag=b'
|
|
88
88
|
```
|
|
89
89
|
|
|
90
90
|
### `useAuthorization(ctx?)`
|
|
@@ -94,13 +94,13 @@ Parses the Authorization header (supports Basic and Bearer).
|
|
|
94
94
|
```ts
|
|
95
95
|
import { useAuthorization } from '@wooksjs/event-http'
|
|
96
96
|
|
|
97
|
-
const { authorization,
|
|
97
|
+
const { authorization, type, credentials, is, basicCredentials } = useAuthorization()
|
|
98
98
|
|
|
99
|
-
if (
|
|
100
|
-
const token =
|
|
99
|
+
if (is('bearer')) {
|
|
100
|
+
const token = credentials() // the raw token string
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
-
if (
|
|
103
|
+
if (is('basic')) {
|
|
104
104
|
const { username, password } = basicCredentials()!
|
|
105
105
|
}
|
|
106
106
|
```
|
|
@@ -110,9 +110,9 @@ if (authIs('basic')) {
|
|
|
110
110
|
| Property | Type | Description |
|
|
111
111
|
| ---------------------- | -------------------------------- | -------------------------------------------------------------- |
|
|
112
112
|
| `authorization` | `string \| undefined` | Raw Authorization header value |
|
|
113
|
-
| `
|
|
114
|
-
| `
|
|
115
|
-
| `
|
|
113
|
+
| `type()` | `string \| null` | Auth scheme: `'Basic'`, `'Bearer'`, etc. |
|
|
114
|
+
| `credentials()` | `string \| null` | Everything after the scheme |
|
|
115
|
+
| `is(type)` | `boolean` | Check auth scheme: `'basic'`, `'bearer'`, or any custom scheme |
|
|
116
116
|
| `basicCredentials()` | `{ username, password } \| null` | Decoded Basic credentials |
|
|
117
117
|
|
|
118
118
|
### `useAccept(ctx?)`
|
|
@@ -122,12 +122,12 @@ Checks the request's `Accept` header for MIME type support. Uses short names (`'
|
|
|
122
122
|
```ts
|
|
123
123
|
import { useAccept } from '@wooksjs/event-http'
|
|
124
124
|
|
|
125
|
-
const { accept,
|
|
125
|
+
const { accept, has } = useAccept()
|
|
126
126
|
|
|
127
|
-
if (
|
|
127
|
+
if (has('json')) {
|
|
128
128
|
/* ... */
|
|
129
129
|
}
|
|
130
|
-
if (
|
|
130
|
+
if (has('image/png')) {
|
|
131
131
|
/* ... */
|
|
132
132
|
}
|
|
133
133
|
```
|
|
@@ -162,10 +162,10 @@ log.info('handling request')
|
|
|
162
162
|
|
|
163
163
|
```ts
|
|
164
164
|
app.post('/admin/action', async () => {
|
|
165
|
-
const {
|
|
166
|
-
if (!
|
|
165
|
+
const { is, credentials } = useAuthorization()
|
|
166
|
+
if (!is('bearer')) throw new HttpError(401)
|
|
167
167
|
|
|
168
|
-
const token =
|
|
168
|
+
const token = credentials()!
|
|
169
169
|
const user = await verifyToken(token)
|
|
170
170
|
if (!user.isAdmin) throw new HttpError(403)
|
|
171
171
|
|
|
@@ -184,7 +184,7 @@ app.get('/hot-path', () => {
|
|
|
184
184
|
const ctx = current()
|
|
185
185
|
const { method } = useRequest(ctx)
|
|
186
186
|
const { getCookie } = useCookies(ctx)
|
|
187
|
-
const {
|
|
187
|
+
const { params } = useUrlParams(ctx)
|
|
188
188
|
// 1 ALS lookup instead of 3
|
|
189
189
|
})
|
|
190
190
|
```
|
|
@@ -40,10 +40,10 @@ run(() => {
|
|
|
40
40
|
// All composables work here
|
|
41
41
|
const { method } = useRequest()
|
|
42
42
|
const { params } = useRouteParams()
|
|
43
|
-
const {
|
|
43
|
+
const { is } = useAuthorization()
|
|
44
44
|
expect(method).toBe('GET')
|
|
45
45
|
expect(params.id).toBe('42')
|
|
46
|
-
expect(
|
|
46
|
+
expect(is('bearer')).toBe(true)
|
|
47
47
|
})
|
|
48
48
|
```
|
|
49
49
|
|