@ublitzjs/core 0.1.1 → 1.0.0

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.
@@ -0,0 +1,249 @@
1
+ import type { BaseHeaders, lowHeaders } from "./http-headers.js";
2
+ import { Buffer } from "node:buffer";
3
+ import { EventEmitter } from "tseep";
4
+ import type { CompressOptions, WebSocket, HttpRequest as uwsHttpRequest, TemplatedApp, HttpResponse as uwsHttpResponse, RecognizedString, us_socket_context_t } from "uWebSockets.js";
5
+ /**
6
+ * function to effortlessly mark response as aborted AND to attach an event emitter, so that you can easily scale the handler. If you don't need event emitter and only some res.aborted - set it by yourself (no overkill for the handler)
7
+ * @param res
8
+ */
9
+ export declare function registerAbort(res: uwsHttpResponse): HttpResponse;
10
+ /**
11
+ * An extended version of uWS.App . It provides you with several features:
12
+ * 1) plugin registration (just like in Fastify);
13
+ * 2) "ready" function and _startPromises array (use it to make your code more asynchronous and safe)
14
+ * 3) "route" function for more descriptive adn extensible way of registering handlers
15
+ * 4) "onError" function (mainly used by @ublitzjs/router)
16
+ */
17
+ export interface Server extends TemplatedApp {
18
+ /**
19
+ * It is same as plugins in Fastify -> you register some functionality in separate function
20
+ * @param plugin
21
+ * @returns itself (for chaining methods)
22
+ */
23
+ register(plugin: (server: this) => void): this;
24
+ /** set global _errHandler (in fact it is used only by @ublitzjs/router) */
25
+ onError(fn: (error: Error, res: HttpResponse, data: any) => any): this;
26
+ _errHandler?(error: Error, res: HttpResponse, data: any): any;
27
+ /**some undocumented property in uWS - get it here */
28
+ addChildAppDescriptor(...any: any[]): this;
29
+ /**a function, which pushes promises to be awaited using "await server.ready()"*/
30
+ awaitLater(...promises: Promise<any>[]): void;
31
+ /**a function, which awaits all promises inside _startPromises array and then clears it*/
32
+ ready: () => Promise<any[]>;
33
+ /**
34
+ * simple array of promises. You can push several inside and await all of them using server.ready() method
35
+ */
36
+ _startPromises: Promise<any>[];
37
+ /**
38
+ * this function allows you to create new handlers but more dynamically than uWS. Best use case - development. By default, the first param you pass includes a method, path, and a controller. However you can configure it for additional properties, which can be consumed on startup by second param - plugins
39
+ * @example
40
+ * server.route<onlyHttpMethods, {deprecated:boolean}>({
41
+ * method:"any",
42
+ * path: "/",
43
+ * controller(res){ res.end("hello") },
44
+ * deprecated:true
45
+ * },
46
+ * [
47
+ * (opts)=>{
48
+ * if(opts.deprecated) console.error("DEPRECATION FOUND", opts.path)
49
+ * }
50
+ * ])
51
+ */
52
+ route<T extends HttpMethods, obj extends object = {}>(opts: routeFNOpts<T> & obj, plugins?: ((param: typeof opts, server: this) => void)[]): this;
53
+ get(pattern: RecognizedString, handler: HttpControllerFn): this;
54
+ post(pattern: RecognizedString, handler: HttpControllerFn): this;
55
+ options(pattern: RecognizedString, handler: HttpControllerFn): this;
56
+ del(pattern: RecognizedString, handler: HttpControllerFn): this;
57
+ patch(pattern: RecognizedString, handler: HttpControllerFn): this;
58
+ put(pattern: RecognizedString, handler: HttpControllerFn): this;
59
+ head(pattern: RecognizedString, handler: HttpControllerFn): this;
60
+ connect(pattern: RecognizedString, handler: HttpControllerFn): this;
61
+ trace(pattern: RecognizedString, handler: HttpControllerFn): this;
62
+ any(pattern: RecognizedString, handler: HttpControllerFn): this;
63
+ ws<UserData>(pattern: RecognizedString, behavior: DocumentedWSBehavior<UserData>): this;
64
+ }
65
+ export type routeFNOpts<T extends HttpMethods> = {
66
+ method: T;
67
+ path: RecognizedString;
68
+ controller: T extends "ws" ? DocumentedWSBehavior<any> : HttpControllerFn;
69
+ };
70
+ /**
71
+ * Utility for making closures. Exists for organizing code and caching values in non-global scope.
72
+ * @param param
73
+ * @returns what you passed
74
+ */
75
+ export declare var closure: <T>(param: () => T) => T;
76
+ /**
77
+ * little more typed response which has:
78
+ * 1) "emitter", that comes from "tseep" package
79
+ * 2) "aborted" flag
80
+ * 3) "finished" flag
81
+ * 4) "collect" function, which comes from original uWS (and isn't documented), but the purpose remains unknown
82
+ * 5) "upgrade" function, though comes from original uWS, must not contain any names, which "DocumentedWS" has (or websocket object). ws.getUserData() return "ws" itself, so setting any data, which overlaps with already existing will impact your workflow. µBlitz.js doesn't add any lsp help here because it will brake "extends uwsHttpResponse" part.
83
+ */
84
+ export interface HttpResponse<UserDataForWS = {}> extends uwsHttpResponse {
85
+ upgrade<UserData = UserDataForWS>(userData: UserData, secWebSocketKey: RecognizedString, secWebSocketProtocol: RecognizedString, secWebSocketExtensions: RecognizedString, context: us_socket_context_t): void;
86
+ /**
87
+ * This method actually exists in original uWebSockets.js, but is undocumented. I'll put it here for your IDE to be happy
88
+ */
89
+ collect: (...any: any[]) => any;
90
+ /**
91
+ * An event emitter, which lets you subscribe several listeners to "abort" event OR your own events, defined with Symbol().
92
+ */
93
+ emitter: EventEmitter<{
94
+ abort: () => void;
95
+ [k: symbol]: (...any: any[]) => void;
96
+ }>;
97
+ /**
98
+ * changes when res.onAborted fires.
99
+ */
100
+ aborted?: boolean;
101
+ /**
102
+ * You should set it manually when ending the response. Particularly useful if some error has fired and you are doubting whether res.aborted is a sufficient flag.
103
+ */
104
+ finished?: boolean;
105
+ }
106
+ /**This HttpRequest is same as original uWS.HttpRequest, but getHeader method is typed for additional tips
107
+ * @example
108
+ * import {lowHeaders} from "@ublitzjs/core"
109
+ * // some handler later
110
+ * req.getHeader<lowHeaders>("content-type")
111
+ */
112
+ export interface HttpRequest extends uwsHttpRequest {
113
+ getHeader<T extends RecognizedString = lowHeaders>(a: T): string;
114
+ }
115
+ export type HttpControllerFn = (res: HttpResponse, req: HttpRequest) => any | Promise<any>;
116
+ /**
117
+ * only http methods without "ws"
118
+ */
119
+ export type onlyHttpMethods = "get" | "post" | "del" | "patch" | "put" | "head" | "trace" | "options" | "connect" | "any";
120
+ /**
121
+ * all httpMethods with "ws" method
122
+ */
123
+ export type HttpMethods = onlyHttpMethods | "ws";
124
+ type MergeObjects<T extends any[]> = T extends [infer First, ...infer Rest] ? First & MergeObjects<Rest extends any[] ? Rest : []> : {};
125
+ /**
126
+ * extends uWS.App() or uWS.SSLApp. See interface Server
127
+ * @param app uWS.App()
128
+ */
129
+ export declare function extendApp<T extends object[]>(app: TemplatedApp, ...rest: T): Server & MergeObjects<T>;
130
+ /**
131
+ * conversion to ArrayBuffer ('cause transferring strings to uWS is really slow)
132
+ */
133
+ export declare function toAB(data: Buffer | string): ArrayBuffer;
134
+ /**
135
+ * Thanks to "acarstoiu" github user for listing such methods here: "https://github.com/uNetworking/uWebSockets.js/issues/1165".
136
+ */
137
+ type WebSocketFragmentation = {
138
+ /** Sends the first frame of a multi-frame message. More fragments are expected (possibly none), followed by a last fragment. Care must be taken so as not to interleave these fragments with whole messages (sent with WebSocket.send) or with other messages' fragments.
139
+ *
140
+ * Returns 1 for success, 2 for dropped due to backpressure limit, and 0 for built up backpressure that will drain over time. You can check backpressure before or after sending by calling getBufferedAmount().
141
+ *
142
+ * Make sure you properly understand the concept of backpressure. Check the backpressure example file.
143
+ */
144
+ sendFirstFragment(message: RecognizedString, isBinary?: boolean, compress?: boolean): number;
145
+ /** Sends a continuation frame of a multi-frame message. More fragments are expected (possibly none), followed by a last fragment. In terms of sending data, a call to this method must follow a call to WebSocket.sendFirstFragment.
146
+ *
147
+ * Returns 1 for success, 2 for dropped due to backpressure limit, and 0 for built up backpressure that will drain over time. You can check backpressure before or after sending by calling getBufferedAmount().
148
+ *
149
+ * Make sure you properly understand the concept of backpressure. Check the backpressure example file.
150
+ */
151
+ sendFragment(message: RecognizedString, compress?: boolean): number;
152
+ /** Sends the last continuation frame of a multi-frame message. In terms of sending data, a call to this method must follow a call to WebSocket.sendFirstFragment or WebSocket.sendFragment.
153
+ *
154
+ * Returns 1 for success, 2 for dropped due to backpressure limit, and 0 for built up backpressure that will drain over time. You can check backpressure before or after sending by calling getBufferedAmount().
155
+ *
156
+ * Make sure you properly understand the concept of backpressure. Check the backpressure example file.
157
+ */
158
+ sendLastFragment(message: RecognizedString, compress?: boolean): number;
159
+ };
160
+ export interface DocumentedWS<UserData> extends WebSocket<UserData>, WebSocketFragmentation {
161
+ /**
162
+ * this is an additional property, which saves you from server crashing. In "close" handler you should add "ws.closed = true" and each time you perform any asynchronous work before sending a message run a check "if(ws.closed) { cleanup and quit }"
163
+ * @example
164
+ * import {setTimeout} from "node:timers/promises"
165
+ * server.ws("/", {
166
+ * close(ws){
167
+ * ws.closed = true;
168
+ * },
169
+ * async message(ws){
170
+ * await setTimeout(100); // simulate some db query
171
+ * if(!ws.closed) ws.send("handled message", false)
172
+ * }
173
+ * })
174
+ * */
175
+ closed: boolean;
176
+ /**
177
+ * an additional property which might save websocket from overexhaustion
178
+ * */
179
+ drainEvent: Promise<void> | undefined;
180
+ /**
181
+ * an additional property to monitor queued messages, which can't be sent due to overexhaustion (need to wait for drain).
182
+ **/
183
+ queue: number;
184
+ }
185
+ export interface DocumentedWSBehavior<UserData> {
186
+ /** Maximum length of received message. If a client tries to send you a message larger than this, the connection is immediately closed. Defaults to 16 * 1024. */
187
+ maxPayloadLength?: number;
188
+ /** Whether or not we should automatically close the socket when a message is dropped due to backpressure. Defaults to false. */
189
+ closeOnBackpressureLimit?: boolean;
190
+ /** Maximum number of minutes a WebSocket may be connected before being closed by the server. 0 disables the feature. */
191
+ maxLifetime?: number;
192
+ /** Maximum amount of seconds that may pass without sending or getting a message. Connection is closed if this timeout passes. Resolution (granularity) for timeouts are typically 4 seconds, rounded to closest.
193
+ * Disable by using 0. Defaults to 120.
194
+ */
195
+ idleTimeout?: number;
196
+ /** What permessage-deflate compression to use. uWS.DISABLED, uWS.SHARED_COMPRESSOR or any of the uWS.DEDICATED_COMPRESSOR_xxxKB. Defaults to uWS.DISABLED. */
197
+ compression?: CompressOptions;
198
+ /** Maximum length of allowed backpressure per socket when publishing or sending messages. Slow receivers with too high backpressure will be skipped until they catch up or timeout. Defaults to 64 * 1024. */
199
+ maxBackpressure?: number;
200
+ /** Whether or not we should automatically send pings to uphold a stable connection given whatever idleTimeout. */
201
+ sendPingsAutomatically?: boolean;
202
+ /** Handler for new WebSocket connection. WebSocket is valid from open to close, no errors. */
203
+ open?: (ws: DocumentedWS<UserData>) => void | Promise<void>;
204
+ /** Handler for a WebSocket message. Messages are given as ArrayBuffer no matter if they are binary or not. Given ArrayBuffer is valid during the lifetime of this callback (until first await or return) and will be neutered. */
205
+ message?: (ws: DocumentedWS<UserData>, message: ArrayBuffer, isBinary: boolean) => void | Promise<void>;
206
+ /** Handler for a dropped WebSocket message. Messages can be dropped due to specified backpressure settings. Messages are given as ArrayBuffer no matter if they are binary or not. Given ArrayBuffer is valid during the lifetime of this callback (until first await or return) and will be neutered. */
207
+ dropped?: (ws: DocumentedWS<UserData>, message: ArrayBuffer, isBinary: boolean) => void | Promise<void>;
208
+ /** Handler for when WebSocket backpressure drains. Check ws.getBufferedAmount(). Use this to guide / drive your backpressure throttling. */
209
+ drain?: (ws: DocumentedWS<UserData>) => void;
210
+ /** Handler for close event, no matter if error, timeout or graceful close. You may not use WebSocket after this event. Do not send on this WebSocket from within here, it is closed. */
211
+ close?: (ws: DocumentedWS<UserData>, code: number, message: ArrayBuffer) => void;
212
+ /** Handler for received ping control message. You do not need to handle this, pong messages are automatically sent as per the standard. */
213
+ ping?: (ws: DocumentedWS<UserData>, message: ArrayBuffer) => void;
214
+ /** Handler for received pong control message. */
215
+ pong?: (ws: DocumentedWS<UserData>, message: ArrayBuffer) => void;
216
+ /** Handler for subscription changes. */
217
+ subscription?: (ws: DocumentedWS<UserData>, topic: ArrayBuffer, newCount: number, oldCount: number) => void;
218
+ /** Upgrade handler used to intercept HTTP upgrade requests and potentially upgrade to WebSocket.
219
+ * See UpgradeAsync and UpgradeSync example files.
220
+ */
221
+ upgrade?: (res: HttpResponse<UserData>, req: HttpRequest, context: us_socket_context_t) => void | Promise<void>;
222
+ }
223
+ export type DeclarativeResType = {
224
+ writeHeader(key: string, value: string): DeclarativeResType;
225
+ writeQueryValue(key: string): DeclarativeResType;
226
+ writeHeaderValue(key: string): DeclarativeResType;
227
+ /**
228
+ * Write a chunk to the precompiled response
229
+ */
230
+ write(value: string): DeclarativeResType;
231
+ writeParameterValue(key: string): DeclarativeResType;
232
+ /**
233
+ * Method to finalize forming a response.
234
+ */
235
+ end(value: string): any;
236
+ writeBody(): DeclarativeResType;
237
+ /**
238
+ * additional method from µBlitz.js
239
+ */
240
+ writeHeaders<Opts extends BaseHeaders>(headers: Opts): DeclarativeResType;
241
+ };
242
+ /**
243
+ * Almost nothing different from uWS.DeclarativeResponse. The only modification - writeHeaders method (several methods, typescript intellisense)
244
+ */
245
+ export declare var DeclarativeResponse: {
246
+ new (): DeclarativeResType;
247
+ };
248
+ export * from "./http-codes.js";
249
+ export * from "./http-headers.js";
package/package.json CHANGED
@@ -1,24 +1,41 @@
1
1
  {
2
2
  "name": "@ublitzjs/core",
3
- "version": "0.1.1",
3
+ "version": "1.0.0",
4
+ "types": "./dist/types/index.d.ts",
4
5
  "exports": {
5
- "types": "./types/index.d.ts",
6
- "require": "./cjs/index.cjs",
7
- "import": "./mjs/index.mjs"
6
+ "types": "./dist/types/index.d.ts",
7
+ "require": "./dist/cjs/index.js",
8
+ "import": "./dist/esm/index.js"
8
9
  },
9
10
  "dependencies": {
10
11
  "tseep": "^1.3.1",
11
- "uWebSockets.js": "github:uNetworking/uWebSockets.js#v20.56.0"
12
+ "uWebSockets.js": "github:uNetworking/uWebSockets.js#v20.57.0"
12
13
  },
13
14
  "publishConfig": {
14
15
  "access": "public"
15
16
  },
16
17
  "devDependencies": {
17
- "undici": "^7.16.0",
18
+ "@babel/cli": "^7.28.6",
19
+ "@babel/core": "^7.29.0",
20
+ "@babel/plugin-transform-modules-commonjs": "^7.28.6",
21
+ "@types/node": "^25.2.1",
22
+ "@types/ws": "^8.18.1",
18
23
  "esbuild": "^0.25.12",
24
+ "tsd": "^0.33.0",
19
25
  "vitest": "^4.0.8",
20
26
  "ws": "^8.18.3"
21
27
  },
28
+ "scripts": {
29
+ "trick-tsd": "bun link && bun link @ublitzjs/core",
30
+ "build:esm": "tsc -p tsconfig.esm.json && echo '{\"type\": \"module\"}' > dist/esm/package.json",
31
+ "build:cjs": "babel dist/esm --out-dir dist/cjs",
32
+ "build:types": "tsc -p tsconfig.types.json",
33
+ "build": "npm run build:types && npm run build:esm && npm run build:cjs",
34
+ "test": "tsd && vitest run"
35
+ },
36
+ "tsd": {
37
+ "directory": "tests"
38
+ },
22
39
  "repository": {
23
40
  "type": "git",
24
41
  "url": "https://github.com/ublitzjs/core.git"
@@ -32,11 +49,14 @@
32
49
  "ublitzjs",
33
50
  "uWebSockets.js",
34
51
  "uws",
52
+ "typescript",
35
53
  "documentation",
36
54
  "http",
55
+ "websockets",
37
56
  "headers",
38
57
  "codes",
39
58
  "development",
40
- "asynchronous code"
59
+ "asynchronous code",
60
+ "µBlitz.js"
41
61
  ]
42
62
  }
@@ -0,0 +1,94 @@
1
+ "use strict";
2
+ import { toAB } from "./index.js";
3
+ var c405Message = toAB("Method is not allowed");
4
+ var allowHeader = toAB("Allow");
5
+ var checkHeader = toAB("content-length");
6
+ var checkMessage = toAB("Content-Length is required to be > 0 and to be an integer");
7
+ import type { HttpResponse as uwsHttpResponse } from "uWebSockets.js";
8
+ import type { HttpRequest, HttpMethods } from "./index.ts";
9
+ /**
10
+ * If something wrong is to content-length, sends 411 code and throws error with a "cause" == { CL : string}, sets res.finished = true
11
+ */
12
+ export function checkContentLength(
13
+ res: uwsHttpResponse,
14
+ req: HttpRequest
15
+ ): number {
16
+ var header = req.getHeader(checkHeader);
17
+ var CL: number;
18
+ if (!header || !Number.isInteger(CL = Number(header))) {
19
+ res.finished = true;
20
+ res.cork(() => res.writeStatus(c411).end(checkMessage));
21
+ throw new Error("Wrong content-length", { cause: { CL: header} });
22
+ }
23
+ return CL;
24
+ }
25
+ /**
26
+ * sends http 400 and throws an Error with "causeForYou", sets res.finished = true
27
+ */
28
+ export function badRequest(
29
+ res: uwsHttpResponse,
30
+ error: string,
31
+ causeForYou: string
32
+ ): void {
33
+ res.finished = true;
34
+ if (!res.aborted) res.cork(() => res.writeStatus(c400).end(toAB(error)));
35
+ throw new Error("Bad request", { cause: causeForYou });
36
+ }
37
+ /**
38
+ * sends http 413, but doesn't throw an Error, sets res.finished = true
39
+ */
40
+ export function tooLargeBody(res: uwsHttpResponse, limit: number): void {
41
+ var message = toAB("Body is too large. Limit in bytes - " + limit);
42
+ if (!res.aborted) res.cork(() => res.writeStatus(c413).end(message));
43
+ res.finished = true;
44
+ }
45
+ /**
46
+ * Constructs function, which sends http 405 and sets http Allow header with all methods you passed.
47
+ * It ignores "ws" and replaces "del" on "DELETE"
48
+ */
49
+ export function seeOtherMethods(
50
+ methodsArr: HttpMethods[]
51
+ ): (res: uwsHttpResponse, req: any) => any {
52
+ if(new Set(methodsArr).size != methodsArr.length) throw new Error("the methods repeat")
53
+ var arr: string[] = []
54
+ loop: for(var method of methodsArr){
55
+ switch(method){
56
+ case "ws": continue loop;
57
+ case "del": arr.push("DELETE"); break;
58
+ default: arr.push(method.toUpperCase())
59
+ }
60
+ }
61
+ var methods = toAB(arr.join(", "));
62
+ return (res) =>
63
+ res.writeStatus(c405).writeHeader(allowHeader, methods).end(c405Message);
64
+ }
65
+
66
+ /**
67
+ * Constructs the function, which sets 404 http code and sends the message you have specified
68
+ */
69
+ export function notFoundConstructor(
70
+ message: string = "Not found"
71
+ ): (res: uwsHttpResponse, req: any) => any {
72
+ var mes = toAB(message);
73
+ return (res) => res.writeStatus(c404).end(mes, true);
74
+ }
75
+ /**
76
+ * code: required content length
77
+ */
78
+ export var c411 = toAB("411");
79
+ /**
80
+ * code: bad request
81
+ */
82
+ export var c400 = toAB("400");
83
+ /**
84
+ * code: payload too large
85
+ */
86
+ export var c413 = toAB("413");
87
+ /**
88
+ * code: method not allowed
89
+ */
90
+ export var c405 = toAB("405");
91
+ /**
92
+ * code: not found
93
+ */
94
+ export var c404 = toAB("404");
@@ -1,8 +1,23 @@
1
- import type { HttpResponse } from "./index";
1
+ "use strict";
2
+ import { toAB } from "./index.js";
3
+ var helmetHeaders: helmetHeadersT = {
4
+ "X-Content-Type-Options": "nosniff",
5
+ "X-DNS-Prefetch-Control": "off",
6
+ "X-Frame-Options": "DENY",
7
+ "Referrer-Policy": "same-origin",
8
+ "X-Permitted-Cross-Domain-Policies": "none",
9
+ "X-Download-Options": "noopen",
10
+ "Cross-Origin-Resource-Policy": "same-origin",
11
+ "Cross-Origin-Opener-Policy": "same-origin",
12
+ "Cross-Origin-Embedder-Policy": "require-corp",
13
+ "Origin-Agent-Cluster": "?1",
14
+ //"Content-Security-Policy-Report-Only":"",
15
+ //"Strict-Transport-Security":`max-age=${60 * 60 * 24 * 365}; includeSubDomains`,
16
+ };
2
17
  import type { HttpResponse as uwsHttpResponse } from "uWebSockets.js";
3
18
  type helmetHeadersT = {
4
19
  /**
5
- * By adding this header you can declare that your site should only load resources that have explicitly opted-in to being loaded across origins.
20
+ * By adding this header you can declare that your site should only load resources that have explicitly opted-in to being loaded across origin.
6
21
  * "require-corp" LETS YOU USE new SharedArrayBuffer()
7
22
  * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Cross-Origin-Embedder-Policy
8
23
  */
@@ -70,7 +85,7 @@ type helmetHeadersT = {
70
85
  /**
71
86
  *@deprecated
72
87
  * */
73
- "X-XSS-Protection": string;
88
+ "X-XSS-Protection"?: string;
74
89
  };
75
90
  type CORSHeader = {
76
91
  /**
@@ -949,46 +964,70 @@ export type BaseHeaders = Partial<
949
964
  */
950
965
  export class HeadersMap<Opts extends BaseHeaders> extends Map {
951
966
  public currentHeaders: undefined | Opts;
952
- constructor(opts: Opts);
967
+ constructor(opts: Opts) {
968
+ super();
969
+ this.currentHeaders = opts;
970
+ };
953
971
  /**
954
972
  * remove several headers from this map. Use BEFORE map.prepare(), because it will compare them by location in memory (string !== ArrayBuffer)
955
973
  * @example HeadersMap.default.remove("Content-Security-Policy", "X-DNS-Prefetch-Control", ...otherHeaders).prepare()
956
974
  */
957
- remove(...keys: (keyof Opts)[]): this;
975
+ remove(...keys: (keyof Opts)[]): this {
976
+ for (const key of keys) delete this.currentHeaders![key];
977
+ return this;
978
+ }
958
979
  /**
959
980
  * last function before "going to response". It converts all strings to ArrayBuffers, so you should delete unwanted headers before it
960
981
  * @returns function, which sets all headers on the response.
961
982
  * @example
962
983
  * new HeadersMap({...HeadersMap.baseObj,"a":"a"}).remove("a").prepare();
963
984
  */
964
- prepare(): (res: uwsHttpResponse) => HttpResponse;
985
+ prepare<T extends uwsHttpResponse>(){
986
+ for (const key in this.currentHeaders)
987
+ this.set(toAB(key), toAB(this.currentHeaders[key]!));
988
+ delete this.currentHeaders;
989
+ return (res: T) => {
990
+ for(var pair of this) res.writeHeader(pair[0], pair[1])
991
+ return res;
992
+ }
993
+ }
965
994
  /**
966
- * write all static headers to response. Use AFTER map.prepare function, if you want speed.
995
+ * write all static headers to response. Use BEFORE map.prepare function, because this function requires "currentHeaders" object.
967
996
  * @example
968
997
  * headersMap.toRes(res);
969
- * // if you want dynamic headers, use BASE:
970
- * res.writeHeader(toAB(headerVariable),toAB(value))
971
998
  */
972
- toRes(res: uwsHttpResponse): HttpResponse;
999
+ toRes<T extends uwsHttpResponse>(res: T): T{
1000
+ var key: keyof Opts
1001
+ for (key in this.currentHeaders) res.writeHeader(key, this.currentHeaders![key]!);
1002
+ return res;
1003
+ }
973
1004
 
974
1005
  /**
975
- * obj, containing basic headers, which u can use as a background for own headers
1006
+ * obj, containing basic headers, which u can use as a background for own headers. It is mutable, but doing so will modify "HeadersMap.default" behavior
976
1007
  * @example
977
1008
  * new HeadersMap({...HeadersMap.baseObj, "ownHeader":"hello world"}).remove("X-Download-Options")
978
1009
  */
979
- static baseObj: helmetHeadersT;
1010
+ static baseObj: helmetHeadersT = helmetHeaders;
980
1011
  /**
981
- * map with default headers
1012
+ * this is same as "toRes", but it uses HeadersMap.baseObj
982
1013
  */
983
- static default: (res: uwsHttpResponse) => HttpResponse;
1014
+ static default<T extends uwsHttpResponse>(res: T): T {
1015
+ var key: keyof typeof HeadersMap.baseObj
1016
+ for (key in HeadersMap.baseObj) res.writeHeader(key, HeadersMap.baseObj[key]!);
1017
+ return res;
1018
+ }
984
1019
  }
985
1020
  /**
986
1021
  * This function creates Content-Security-Policy string.
987
1022
  */
988
- export function setCSP<T extends CSP>(
989
- mainCSP: T,
990
- ...remove: (keyof CSP)[]
991
- ): string;
1023
+ export function setCSP<T extends CSP>(mainCSP: T, ...remove: (keyof CSP)[]): string {
1024
+ var CSPstring = "";
1025
+ for (const dir of remove) delete mainCSP[dir];
1026
+ var key: keyof T;
1027
+ for (key in mainCSP)
1028
+ CSPstring += (key as string) + " " + (mainCSP[key] as string[]).join(" ") + "; ";
1029
+ return CSPstring;
1030
+ }
992
1031
  type CSP = Partial<
993
1032
  typeof CSPDirs & {
994
1033
  /**
@@ -1073,6 +1112,24 @@ export var CSPDirs: {
1073
1112
  * specifies valid sources for loading media using the <audio> and <video> elements.
1074
1113
  */
1075
1114
  "media-src": string[];
1115
+ } = {
1116
+ "default-src": ["'self'"],
1117
+ "base-uri": ["'self'"],
1118
+ "font-src": ["'self'"],
1119
+ "form-action": ["'self'"],
1120
+ "frame-ancestors": ["'none'"],
1121
+ "img-src": ["'self'"],
1122
+ "connect-src": ["'self'"],
1123
+ "object-src": ["'none'"],
1124
+ "script-src": ["'self'"],
1125
+ "script-src-attr": ["'none'"],
1126
+ "script-src-elem": ["'self'"],
1127
+ "style-src": ["'self'"],
1128
+ "style-src-attr": ["'none'"],
1129
+ "style-src-elem": ["'self'"],
1130
+ "trusted-types": ["'none'"],
1131
+ "worker-src": ["'self'"],
1132
+ "media-src": ["'self'"],
1076
1133
  };
1077
1134
  export type lowHeaders = Lowercase<
1078
1135
  keyof (simpleHeaders & helmetHeadersT & experimentalHeaders & CORSHeader)